From 727abd32357f6eba4c3416615b4b0f41ab4cdf48 Mon Sep 17 00:00:00 2001 From: gered Date: Sun, 31 Mar 2019 15:57:52 -0400 Subject: [PATCH] initial commit from fte-20010819-src.zip sources --- Makefile | 25 + fte.in | 17 + src/Makefile | 31 + src/bin2c.cpp | 33 + src/bmps/close.bmp | Bin 0 -> 1806 bytes src/bmps/copy.bmp | Bin 0 -> 1806 bytes src/bmps/cut.bmp | Bin 0 -> 1806 bytes src/bmps/errnext.bmp | Bin 0 -> 1806 bytes src/bmps/errprev.bmp | Bin 0 -> 1806 bytes src/bmps/exit.bmp | Bin 0 -> 1806 bytes src/bmps/last.bmp | Bin 0 -> 1806 bytes src/bmps/next.bmp | Bin 0 -> 1806 bytes src/bmps/open.bmp | Bin 0 -> 1806 bytes src/bmps/paste.bmp | Bin 0 -> 1806 bytes src/bmps/pastecol.bmp | Bin 0 -> 1806 bytes src/bmps/prev.bmp | Bin 0 -> 1806 bytes src/bmps/redo.bmp | Bin 0 -> 1806 bytes src/bmps/save.bmp | Bin 0 -> 1806 bytes src/bmps/tagfind.bmp | Bin 0 -> 1806 bytes src/bmps/tagnext.bmp | Bin 0 -> 1806 bytes src/bmps/tagpop.bmp | Bin 0 -> 1806 bytes src/bmps/tagprev.bmp | Bin 0 -> 1806 bytes src/bmps/undo.bmp | Bin 0 -> 1806 bytes src/c_bind.cpp | 712 +++++++ src/c_bind.h | 166 ++ src/c_cmdtab.h | 335 ++++ src/c_color.cpp | 129 ++ src/c_color.h | 58 + src/c_commands.h | 698 +++++++ src/c_config.cpp | 1124 +++++++++++ src/c_config.h | 49 + src/c_desktop.cpp | 162 ++ src/c_desktop.h | 28 + src/c_fconfig.h | 48 + src/c_hilit.cpp | 329 ++++ src/c_hilit.h | 223 +++ src/c_history.cpp | 260 +++ src/c_history.h | 64 + src/c_mode.cpp | 133 ++ src/c_mode.h | 262 +++ src/cfte.cpp | 1789 ++++++++++++++++++ src/cfte.def | 3 + src/clip.h | 28 + src/clip_gpm.cpp | 18 + src/clip_no.cpp | 18 + src/clip_os2.cpp | 71 + src/clip_pm.cpp | 57 + src/clip_pmv.cpp | 439 +++++ src/clip_vio.cpp | 103 ++ src/clip_x11.cpp | 83 + src/clipprog.cpp | 73 + src/clipserv.cpp | 185 ++ src/clipserv.def | 3 + src/cliputil.cpp | 50 + src/cliputil.def | 3 + src/commands.cpp | 30 + src/compkeys.cpp | 457 +++++ src/con_dosx.cpp | 1145 ++++++++++++ src/con_i18n.cpp | 397 ++++ src/con_i18n.h | 32 + src/con_ikcz.h | 390 ++++ src/con_linux.cpp | 1205 ++++++++++++ src/con_nt.cpp | 1925 +++++++++++++++++++ src/con_os2.cpp | 1226 ++++++++++++ src/con_slang.cpp | 1057 +++++++++++ src/con_x11.cpp | 1660 +++++++++++++++++ src/conkbd.h | 77 + src/console.h | 211 +++ src/defcfg.fte | 517 ++++++ src/defcfg2.fte | 264 +++ src/dialog.h | 23 + src/e_block.cpp | 1069 +++++++++++ src/e_buffer.cpp | 983 ++++++++++ src/e_buffer.h | 770 ++++++++ src/e_cmds.cpp | 1346 ++++++++++++++ src/e_djgpp2.cpp | 18 + src/e_file.cpp | 102 + src/e_fold.cpp | 531 ++++++ src/e_line.cpp | 233 +++ src/e_loadsave.cpp | 450 +++++ src/e_mark.cpp | 258 +++ src/e_mark.h | 57 + src/e_os2.cpp | 39 + src/e_print.cpp | 194 ++ src/e_redraw.cpp | 596 ++++++ src/e_regex.cpp | 1116 +++++++++++ src/e_regex.h | 110 ++ src/e_search.cpp | 1153 ++++++++++++ src/e_tags.cpp | 589 ++++++ src/e_tags.h | 31 + src/e_trans.cpp | 269 +++ src/e_undo.cpp | 370 ++++ src/e_undo.h | 43 + src/e_unix.cpp | 87 + src/e_win32.cpp | 39 + src/egui.cpp | 1068 +++++++++++ src/egui.h | 91 + src/feature.h | 93 + src/fnmatch.h | 84 + src/fte-bcc2.mak | 72 + src/fte-bcc5.mak | 63 + src/fte-cygwin-xf86.mak | 103 ++ src/fte-dj2.mak | 54 + src/fte-emx.mak | 80 + src/fte-mngw.mak | 62 + src/fte-msvc.mak | 71 + src/fte-unix.mak | 207 +++ src/fte-vag.mak | 176 ++ src/fte-x2.mak | 134 ++ src/fte-xwin.mak | 246 +++ src/fte.cnf | Bin 0 -> 139621 bytes src/fte.cpp | 330 ++++ src/fte.def | 3 + src/fte.h | 64 + src/fte2.cpp | 525 ++++++ src/ftepm.def | 3 + src/ftepm.rc | 30 + src/ftever.h | 11 + src/g_draw.cpp | 279 +++ src/g_menu.cpp | 80 + src/g_motif.cpp | 2003 ++++++++++++++++++++ src/g_nodlg.cpp | 32 + src/g_pm.cpp | 3891 +++++++++++++++++++++++++++++++++++++++ src/g_qt.cpp | 2138 +++++++++++++++++++++ src/g_qt.moc | 129 ++ src/g_qt_dlg.cpp | 214 +++ src/g_qt_dlg.moc | 50 + src/g_text.cpp | 1232 +++++++++++++ src/gui.cpp | 41 + src/gui.h | 214 +++ src/h_ada.cpp | 130 ++ src/h_c.cpp | 1340 ++++++++++++++ src/h_catbs.cpp | 52 + src/h_diff.cpp | 55 + src/h_fte.cpp | 170 ++ src/h_html.cpp | 143 ++ src/h_ipf.cpp | 107 ++ src/h_make.cpp | 72 + src/h_merge.cpp | 59 + src/h_msg.cpp | 150 ++ src/h_pascal.cpp | 139 ++ src/h_perl.cpp | 598 ++++++ src/h_plain.cpp | 95 + src/h_rexx.cpp | 391 ++++ src/h_sh.cpp | 256 +++ src/h_simple.cpp | 239 +++ src/h_tex.cpp | 89 + src/i_ascii.cpp | 129 ++ src/i_ascii.h | 30 + src/i_choice.cpp | 186 ++ src/i_choice.h | 38 + src/i_complete.cpp | 413 +++++ src/i_complete.h | 47 + src/i_input.cpp | 305 +++ src/i_input.h | 44 + src/i_key.cpp | 66 + src/i_key.h | 32 + src/i_modelview.cpp | 75 + src/i_modelview.h | 40 + src/i_oview.cpp | 106 ++ src/i_oview.h | 57 + src/i_search.cpp | 188 ++ src/i_search.h | 43 + src/i_view.cpp | 338 ++++ src/i_view.h | 57 + src/icons/ftepm.ico | Bin 0 -> 3344 bytes src/indent.cpp | 37 + src/log.cpp | 170 ++ src/log.h | 306 +++ src/memicmp.cpp | 32 + src/menu_text.cpp | 666 +++++++ src/mkdefcfg.pl | 43 + src/namemaps.h | 27 + src/o_buffer.cpp | 1512 +++++++++++++++ src/o_buflist.cpp | 167 ++ src/o_buflist.h | 32 + src/o_directory.cpp | 454 +++++ src/o_directory.h | 55 + src/o_list.cpp | 623 +++++++ src/o_list.h | 94 + src/o_messages.cpp | 632 +++++++ src/o_messages.h | 90 + src/o_model.cpp | 190 ++ src/o_model.h | 176 ++ src/o_modemap.cpp | 174 ++ src/o_modemap.h | 45 + src/o_routine.cpp | 121 ++ src/o_routine.h | 34 + src/objs.inc | 143 ++ src/pm_tool.cpp | 403 ++++ src/pm_tool.h | 35 + src/pmdlg.h | 26 + src/pmdlg.rc | 81 + src/port.c | 668 +++++++ src/port.h | 291 +++ src/portdos.c | 960 ++++++++++ src/s_direct.cpp | 435 +++++ src/s_direct.h | 63 + src/s_files.cpp | 469 +++++ src/s_files.h | 53 + src/s_util.cpp | 239 +++ src/s_util.h | 34 + src/simple.fte | 492 +++++ src/sysdep.h | 172 ++ src/view.cpp | 735 ++++++++ 205 files changed, 60009 insertions(+) create mode 100644 Makefile create mode 100644 fte.in create mode 100644 src/Makefile create mode 100644 src/bin2c.cpp create mode 100644 src/bmps/close.bmp create mode 100644 src/bmps/copy.bmp create mode 100644 src/bmps/cut.bmp create mode 100644 src/bmps/errnext.bmp create mode 100644 src/bmps/errprev.bmp create mode 100644 src/bmps/exit.bmp create mode 100644 src/bmps/last.bmp create mode 100644 src/bmps/next.bmp create mode 100644 src/bmps/open.bmp create mode 100644 src/bmps/paste.bmp create mode 100644 src/bmps/pastecol.bmp create mode 100644 src/bmps/prev.bmp create mode 100644 src/bmps/redo.bmp create mode 100644 src/bmps/save.bmp create mode 100644 src/bmps/tagfind.bmp create mode 100644 src/bmps/tagnext.bmp create mode 100644 src/bmps/tagpop.bmp create mode 100644 src/bmps/tagprev.bmp create mode 100644 src/bmps/undo.bmp create mode 100644 src/c_bind.cpp create mode 100644 src/c_bind.h create mode 100644 src/c_cmdtab.h create mode 100644 src/c_color.cpp create mode 100644 src/c_color.h create mode 100644 src/c_commands.h create mode 100644 src/c_config.cpp create mode 100644 src/c_config.h create mode 100644 src/c_desktop.cpp create mode 100644 src/c_desktop.h create mode 100644 src/c_fconfig.h create mode 100644 src/c_hilit.cpp create mode 100644 src/c_hilit.h create mode 100644 src/c_history.cpp create mode 100644 src/c_history.h create mode 100644 src/c_mode.cpp create mode 100644 src/c_mode.h create mode 100644 src/cfte.cpp create mode 100644 src/cfte.def create mode 100644 src/clip.h create mode 100644 src/clip_gpm.cpp create mode 100644 src/clip_no.cpp create mode 100644 src/clip_os2.cpp create mode 100644 src/clip_pm.cpp create mode 100644 src/clip_pmv.cpp create mode 100644 src/clip_vio.cpp create mode 100644 src/clip_x11.cpp create mode 100644 src/clipprog.cpp create mode 100644 src/clipserv.cpp create mode 100644 src/clipserv.def create mode 100644 src/cliputil.cpp create mode 100644 src/cliputil.def create mode 100644 src/commands.cpp create mode 100644 src/compkeys.cpp create mode 100644 src/con_dosx.cpp create mode 100644 src/con_i18n.cpp create mode 100644 src/con_i18n.h create mode 100644 src/con_ikcz.h create mode 100644 src/con_linux.cpp create mode 100644 src/con_nt.cpp create mode 100644 src/con_os2.cpp create mode 100644 src/con_slang.cpp create mode 100644 src/con_x11.cpp create mode 100644 src/conkbd.h create mode 100644 src/console.h create mode 100644 src/defcfg.fte create mode 100644 src/defcfg2.fte create mode 100644 src/dialog.h create mode 100644 src/e_block.cpp create mode 100644 src/e_buffer.cpp create mode 100644 src/e_buffer.h create mode 100644 src/e_cmds.cpp create mode 100644 src/e_djgpp2.cpp create mode 100644 src/e_file.cpp create mode 100644 src/e_fold.cpp create mode 100644 src/e_line.cpp create mode 100644 src/e_loadsave.cpp create mode 100644 src/e_mark.cpp create mode 100644 src/e_mark.h create mode 100644 src/e_os2.cpp create mode 100644 src/e_print.cpp create mode 100644 src/e_redraw.cpp create mode 100644 src/e_regex.cpp create mode 100644 src/e_regex.h create mode 100644 src/e_search.cpp create mode 100644 src/e_tags.cpp create mode 100644 src/e_tags.h create mode 100644 src/e_trans.cpp create mode 100644 src/e_undo.cpp create mode 100644 src/e_undo.h create mode 100644 src/e_unix.cpp create mode 100644 src/e_win32.cpp create mode 100644 src/egui.cpp create mode 100644 src/egui.h create mode 100644 src/feature.h create mode 100644 src/fnmatch.h create mode 100644 src/fte-bcc2.mak create mode 100644 src/fte-bcc5.mak create mode 100644 src/fte-cygwin-xf86.mak create mode 100644 src/fte-dj2.mak create mode 100644 src/fte-emx.mak create mode 100644 src/fte-mngw.mak create mode 100644 src/fte-msvc.mak create mode 100644 src/fte-unix.mak create mode 100644 src/fte-vag.mak create mode 100644 src/fte-x2.mak create mode 100644 src/fte-xwin.mak create mode 100644 src/fte.cnf create mode 100644 src/fte.cpp create mode 100644 src/fte.def create mode 100644 src/fte.h create mode 100644 src/fte2.cpp create mode 100644 src/ftepm.def create mode 100644 src/ftepm.rc create mode 100644 src/ftever.h create mode 100644 src/g_draw.cpp create mode 100644 src/g_menu.cpp create mode 100644 src/g_motif.cpp create mode 100644 src/g_nodlg.cpp create mode 100644 src/g_pm.cpp create mode 100644 src/g_qt.cpp create mode 100644 src/g_qt.moc create mode 100644 src/g_qt_dlg.cpp create mode 100644 src/g_qt_dlg.moc create mode 100644 src/g_text.cpp create mode 100644 src/gui.cpp create mode 100644 src/gui.h create mode 100644 src/h_ada.cpp create mode 100644 src/h_c.cpp create mode 100644 src/h_catbs.cpp create mode 100644 src/h_diff.cpp create mode 100644 src/h_fte.cpp create mode 100644 src/h_html.cpp create mode 100644 src/h_ipf.cpp create mode 100644 src/h_make.cpp create mode 100644 src/h_merge.cpp create mode 100644 src/h_msg.cpp create mode 100644 src/h_pascal.cpp create mode 100644 src/h_perl.cpp create mode 100644 src/h_plain.cpp create mode 100644 src/h_rexx.cpp create mode 100644 src/h_sh.cpp create mode 100644 src/h_simple.cpp create mode 100644 src/h_tex.cpp create mode 100644 src/i_ascii.cpp create mode 100644 src/i_ascii.h create mode 100644 src/i_choice.cpp create mode 100644 src/i_choice.h create mode 100644 src/i_complete.cpp create mode 100644 src/i_complete.h create mode 100644 src/i_input.cpp create mode 100644 src/i_input.h create mode 100644 src/i_key.cpp create mode 100644 src/i_key.h create mode 100644 src/i_modelview.cpp create mode 100644 src/i_modelview.h create mode 100644 src/i_oview.cpp create mode 100644 src/i_oview.h create mode 100644 src/i_search.cpp create mode 100644 src/i_search.h create mode 100644 src/i_view.cpp create mode 100644 src/i_view.h create mode 100644 src/icons/ftepm.ico create mode 100644 src/indent.cpp create mode 100644 src/log.cpp create mode 100644 src/log.h create mode 100644 src/memicmp.cpp create mode 100644 src/menu_text.cpp create mode 100644 src/mkdefcfg.pl create mode 100644 src/namemaps.h create mode 100644 src/o_buffer.cpp create mode 100644 src/o_buflist.cpp create mode 100644 src/o_buflist.h create mode 100644 src/o_directory.cpp create mode 100644 src/o_directory.h create mode 100644 src/o_list.cpp create mode 100644 src/o_list.h create mode 100644 src/o_messages.cpp create mode 100644 src/o_messages.h create mode 100644 src/o_model.cpp create mode 100644 src/o_model.h create mode 100644 src/o_modemap.cpp create mode 100644 src/o_modemap.h create mode 100644 src/o_routine.cpp create mode 100644 src/o_routine.h create mode 100644 src/objs.inc create mode 100644 src/pm_tool.cpp create mode 100644 src/pm_tool.h create mode 100644 src/pmdlg.h create mode 100644 src/pmdlg.rc create mode 100644 src/port.c create mode 100644 src/port.h create mode 100644 src/portdos.c create mode 100644 src/s_direct.cpp create mode 100644 src/s_direct.h create mode 100644 src/s_files.cpp create mode 100644 src/s_files.h create mode 100644 src/s_util.cpp create mode 100644 src/s_util.h create mode 100644 src/simple.fte create mode 100644 src/sysdep.h create mode 100644 src/view.cpp diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..d586d1c --- /dev/null +++ b/Makefile @@ -0,0 +1,25 @@ +PREFIX=/usr/local + +BINDIR=$(PREFIX)/bin +LIBDIR=$(PREFIX)/lib/fte +CONFIGDIR=$(LIBDIR)/config + +.PHONY: all install + +all: fte + (cd src ; make unix) + +install: all + sh install + +fte: fte.in Makefile + sed < fte.in >$@ \ + -e "s|@@CONFIGDIR@@|$(CONFIGDIR)|g" \ + -e "s|@@BINDIR@@|$(BINDIR)|g" + chmod a+x $@ + +dist: fte + +clean: + rm -f fte + (cd src ; make -f fte-unix.mak clean) diff --git a/fte.in b/fte.in new file mode 100644 index 0000000..0da8177 --- /dev/null +++ b/fte.in @@ -0,0 +1,17 @@ +#!/bin/sh + +if [ ! -f $HOME/.fterc ] +then + # Is there a .fte/mymain.fte ? If not, create it. + if [ ! -f $HOME/.fte/mymain.fte ] + then + if [ ! -d $HOME/.fte ] + then + mkdir $HOME/.fte + fi + cp @@CONFIGDIR@@/mymain.fte $HOME/.fte/mymain.fte + fi + (cd @@CONFIGDIR@@; @@BINDIR@@/cfte mymain.fte $HOME/.fterc) || exit 1 +fi + +exec @@BINDIR@@/xfte "$@" diff --git a/src/Makefile b/src/Makefile new file mode 100644 index 0000000..f1fe962 --- /dev/null +++ b/src/Makefile @@ -0,0 +1,31 @@ +MAKE=make + +all: + @echo 'What (emx, unix, cygwin, bcc2, win32ms, win32bcc5, win32mingw, djgpp2, vag)?' + +emx: + $(MAKE) -f fte-emx.mak + +unix: + $(MAKE) -f fte-unix.mak + +cygwin: + $(MAKE) -f fte-cygwin-xf86.mak + +bcc2: + $(MAKE) -f fte-bcc2.mak + +win32ms: + nmake /f fte-msvc.mak + +win32mingw: + $(MAKE) -f fte-mngw.mak + +win32bcc5: + $(MAKE) -f fte-bcc5.mak + +djgpp2: + $(MAKE) -f fte-dj2.mak + +vag: + nmake /f fte-vag.mak diff --git a/src/bin2c.cpp b/src/bin2c.cpp new file mode 100644 index 0000000..9d05af6 --- /dev/null +++ b/src/bin2c.cpp @@ -0,0 +1,33 @@ +#include "sysdep.h" + +#define BUFLEN (64 * 1024) + +unsigned char buf[BUFLEN]; + +int main(int argc, char **argv) { + int fd; + int i, n = 1, len; + + if (argc != 2) { + fprintf(stderr, "Usage: %s filename\n", argv[0]); exit(1); + } + + if ((fd = open(argv[1], O_RDONLY | O_BINARY)) == -1) { + fprintf(stderr, "Open: %s, error=%d\n", argv[1], errno); + exit(1); + } + printf("/* do not edit */\nunsigned char DefaultConfig[] = {\n"); + while ((len = read(fd, buf, BUFLEN)) > 0) { + for (i = 0; i < len; i++) { + printf("0x%02.02X", buf[i]); + if (n++ % 10) { + printf(", "); + } else { + printf(",\n"); + } + } + } + close(fd); + printf("\n};\n"); + return 0; +} diff --git a/src/bmps/close.bmp b/src/bmps/close.bmp new file mode 100644 index 0000000000000000000000000000000000000000..07439bd058e9acbf61ff7d37498437873120ad4a GIT binary patch literal 1806 zcmeH^Q3`-C3`6x69!LDwqt7cjt&~#Iw1R&+980^GY|Lfd1{vo%_c`5jyi_k9jJCJ` zE53j{YX#<{{vIAx!BQp#^bUk1TWYrg@~~-LP&=0^p(SdnS4BjoeNE^hg$eLVjtvn_ tPK>rRL;zPtF4u=H*mOo)5}s_?gsxLE1u7wOXc{GeyCE#=B(#69c>tOwo#_Ao literal 0 HcmV?d00001 diff --git a/src/bmps/copy.bmp b/src/bmps/copy.bmp new file mode 100644 index 0000000000000000000000000000000000000000..d6655694eedfdf287fb75a083503acfaf16b8c89 GIT binary patch literal 1806 zcmeHGZ4Q7S2(?>uoYwz3RO@_oBzt6I8i?y_t1X5T6&^grw(DIGnj4II8`WxIaX_Yd z`kdPIc64lK=e@4Z#W(=*d7%_P&SUq(mw)A+5jzfJsPQxo1*#%nztlf~xn2*`VMFi3 zv=}rtvge=66U7pv@H@&lgq2AAt=NW#QBQmXPmYqt+i*}}LO#EcT+|%^plzgLU-dUO QCDaL!fRDgfjHI_8Eev~@{Qv*} literal 0 HcmV?d00001 diff --git a/src/bmps/cut.bmp b/src/bmps/cut.bmp new file mode 100644 index 0000000000000000000000000000000000000000..604a849171e0cff02d36c9cefd3f778587bd9aba GIT binary patch literal 1806 zcmeHDTMmOT3>&xLIEer4P>A!vm1bsSMQs{Vep%Fl>)7sNet%x9<3C}J=Nx_ri;mj% z?LTh30H4?zYsPk63=8=HxW}nMjcPViITw_fl0ktlx2ANu!VGu$)Kt|uvAcQS} zmNMYs)uni_K-_9E1YJfE^qxu~umhvGUDv7Lf}Tbt2qdH2kRtOkDhTO{(%}VYw_mjc XY}alV2$C{fTrXVjVwt?sx}J=`ASB)! literal 0 HcmV?d00001 diff --git a/src/bmps/errnext.bmp b/src/bmps/errnext.bmp new file mode 100644 index 0000000000000000000000000000000000000000..1993fd2cb2f629b3e6f8af20a74f75a34be843ba GIT binary patch literal 1806 zcmd6jZ4QD!5JUAA9>?%sj*eHNI^?C!Wm@jd?-giB>?YX{5hYzmh zx%~gF@7Y_@E$5u)r({ct*E%<0ngld%^dXboPzX3QVOc27E_%5$8G+Y2N5-qVOe=R0 zPd16#rt0v>#BNe9x-%j$tWP~?{60Pr&QPz7E6BC3kaY12uKVBy6#YqdGjh9n7Kinz S2eDWk`{8#n=zLF>90n^!R3~l# literal 0 HcmV?d00001 diff --git a/src/bmps/errprev.bmp b/src/bmps/errprev.bmp new file mode 100644 index 0000000000000000000000000000000000000000..e12560991ef2ce4d260e15a0184173cf47213114 GIT binary patch literal 1806 zcmd6iQ4T;b5Jb6!!b0Yj$etB8H)2mQYH+vf3c z!IpLTx8M!T@7ZlGD*iS6o>HFb9H8*V>osZA_62ASr-9?i&zo(I>$5+A29)g`6d}) rjRb#%EnM+}F=$|@K)_-F*9b7Cu1B~k9+}D_qAK|Slc>P$Rxp7B{y$nZ literal 0 HcmV?d00001 diff --git a/src/bmps/next.bmp b/src/bmps/next.bmp new file mode 100644 index 0000000000000000000000000000000000000000..604d7bf2af04f4e8d7af99f33cb1268c21fb0cd3 GIT binary patch literal 1806 zcmZ?r^<#hl5bXfO5>U(tW&t@QfOF^1jiNyk0>Egaic28TPq|U>WJIA+aC0d4;6NFL zY%hK`{;!b0Yj$etB8H)2mQYH+vf3c z!IpLTx8M!T@7ZlGD*iSl>?FjhGRae%W>37a)^@>L~Cyq2001k3n%6-jusQ+NRfyEkzz`t--KL%!bFUqm$XPHkGY9EBj$gO7Hb=~F$7VxFO literal 0 HcmV?d00001 diff --git a/src/bmps/pastecol.bmp b/src/bmps/pastecol.bmp new file mode 100644 index 0000000000000000000000000000000000000000..66a957a17e7993b56e0e5a119f5e7f2f7ae77dd3 GIT binary patch literal 1806 zcmd6l(G9~O3`E;4I!=}UcBm@zB_q+JSE0io;~-Uy1;jYq!>)R5!2RdR@v5=`4sI}CCX&&i5(!q0y>+AQ+?MVl3cNMF%iBfy~(uJmI$H3Y`=YL%BfbDGeOnBz#1I0=rm mTCJRo18+_Dor1RD=Mb;2)eIDURrjqy%|S?pwnX=?-xc40zNEnb literal 0 HcmV?d00001 diff --git a/src/bmps/prev.bmp b/src/bmps/prev.bmp new file mode 100644 index 0000000000000000000000000000000000000000..d3b560d03f69e13978a493a77192f3981f53e5c5 GIT binary patch literal 1806 zcmZ?r^<#hl5bXfO5>U(tW&t@QfOF^1jiSL20>C(<+!>IFr_daD>Y>COxFMAIYj7HZ z>?%w)oFJqnk*@+a5Tc?}9mhb9y~&21Y#N zZ(bcZLU2KWQbm+#&i>EHQMFqL^g+I*78I(Z(WNW69|h x>vZ|kJdY@CM>xjSY=T5H6t=7c=Oiu+h)F=l`q!cYJ_xt@FxB(n%t`z_P literal 0 HcmV?d00001 diff --git a/src/bmps/save.bmp b/src/bmps/save.bmp new file mode 100644 index 0000000000000000000000000000000000000000..cb71310ff4f4147136677c2c24ec31bae0db198c GIT binary patch literal 1806 zcmZ?r^<#hl5bXfO5>U(tW&t@QfOF^14R6%Kz(5AV3=^Os|AB~j0JeA39Gn3*8a_CK z1}s6J@PVXi;z(c?z?Ghnvlv!yL9-9oB67?DhX&B(k!%ifAcMjI8$eTo8DGOp1OUed B)n@949$nt|iX%Kj|IUcX%NM182D{ z|GGZq?ipl4tz$?4?O+^G8!}H-c%x5MmBTqc>PsVmJO&Ihn0;W5kMH6*&)lDfY=B%2 zgA&GpvV@Ky17H%M$}03)$F9tLX0U3e$cAkxcl?|BCi$-Q#lQH_C4*?8N&HIIX`M|f j{j|OML*{H|VwX=mn@ZpZz5>!z%xLIces>$~zFq$SPl1lI literal 0 HcmV?d00001 diff --git a/src/bmps/tagnext.bmp b/src/bmps/tagnext.bmp new file mode 100644 index 0000000000000000000000000000000000000000..66daea0a6b4e40bdeb64c9545be94eae78cc8bb3 GIT binary patch literal 1806 zcmdUrQ4WGY3@5PN5?B!DVe-%rCXH**gzQC*V%>p_!xY>pEtX&%YB*2UcOk< zbK2|DQ~rDglQ64HQ6UM?GJtg!_P|buV9 P(SH@0zvmDG2dTUO$xwU` literal 0 HcmV?d00001 diff --git a/src/bmps/tagpop.bmp b/src/bmps/tagpop.bmp new file mode 100644 index 0000000000000000000000000000000000000000..03532e6ad271277bc9562e989edde47b90889f3e GIT binary patch literal 1806 zcmc(aQ4Yc|3`5H;I1b_;jy{eAflNv#DfD+bQ; zTK;u)%jq4=gjvOq0ODX2FzYgH1-#QIOy%+%AIl}kKwbj|8O$6w$4B3yIPcuwhpvM> z4ucX#fpsYrLps33LFihkvx-%j`OIKdw&<#@<5FLe9eu|?C#ui8HNDe5Ii-9;N$Nhw eeaa_n%AFX4U3P6%YDUQ}H;*$M&+wAjUwU4doil@$vuSIcDzXp(=>u zD0HHDuqsE-h`<~lTc;TPFltjI5=KZ(27RJ4iZc9s(=!O;Ch31wR;>W3j}2ngGEq;b SN-15JHel5P(h6E_x9e{KVtfw( literal 0 HcmV?d00001 diff --git a/src/bmps/undo.bmp b/src/bmps/undo.bmp new file mode 100644 index 0000000000000000000000000000000000000000..b9cfbcad823b8f108e90500bf0d3b1567b5d9694 GIT binary patch literal 1806 zcmeH^-3@>s41{qD$1%R^RL+MZ>FJq<@Mo*MDJf9!_0NHYZdlRa}0o;UwI1O=VLZ$xkygBNnC77fuC8s1KMA>bKvmAkFI202V ut@= CMacros)) + return "?INVALID?"; + if (Macros[Command].Name) + return Macros[Command].Name; + else + return "?NONE?"; + } + for (int i = 0; i < int(sizeof(Command_Table) / sizeof(Command_Table[0])); i++) + if (Command_Table[i].CmdId == Command) + return Command_Table[i].Name; + return "?invalid?"; +} + +int CmdNum(char *Cmd) { + int i; + + for (i = 0; + i < int(sizeof(Command_Table) / sizeof(Command_Table[0])); + i++) + if (strcmp(Cmd, Command_Table[i].Name) == 0) + return Command_Table[i].CmdId; + for (i = 0; i < CMacros; i++) + if (Macros[i].Name && (strcmp(Cmd, Macros[i].Name)) == 0) + return i | CMD_EXT; + return 0; // Nop +} + +EMode *FindMode(const char *Name) { + EMode *m = Modes; + + //fprintf(stderr, "Searching mode %s\n", Name); + while (m) { + if (strcmp(Name, m->fName) == 0) + return m; + m = m->fNext; + } + return 0; +} + +EEventMap *FindEventMap(const char *Name) { + EEventMap *m = EventMaps; + + //fprintf(stderr, "Searching map %s\n", Name); + while (m) { + if (strcmp(Name, m->Name) == 0) + return m; + m = m->Next; + } + return 0; +} + +EEventMap *FindActiveMap(EMode *Mode) { + while (Mode) { + if (Mode->fEventMap) + return Mode->fEventMap; + Mode = Mode->fParent; + } + return 0; +} + +EKey *SetKey(EEventMap *aMap, const char *aKey) { + EKeyMap **map = &aMap->KeyMap, *pm, *parent = 0; + EKey *k; + char Key[256]; + char *p, *d; + EEventMap *xm = aMap; + + // printf("Setting key %s\n", Key); + strcpy(Key, aKey); + + // if mode has parent, get parent keymap + while (xm && xm->Parent && (parent == 0)) { + parent = xm->Parent->KeyMap; + // printf("%s : %s : %d\n", xm->fName, xm->fParent->fName, parent); + xm = xm->Parent; + } + + d = p = Key; + while (d) { + // parse key combination + p = d; + d = strchr(p, '_'); + if (d) { + if (d[1] == 0 || d[1] == '_') + d++; + + if (*d == 0) + d = 0; + else { + *d = 0; + d++; + } + } + + // if lastkey + + if (d == 0) { + k = new EKey(p); + if (*map) { + (*map)->AddKey(k); + } else { + *map = new EKeyMap(); + (*map)->fParent = parent; + (*map)->AddKey(k); + } + return k; + + } else { + // if introductory key + + if (*map == 0) { // first key in mode, create map + // printf("new map key = %s, parent %d\n", p, parent); + k = new EKey(p, 0); + *map = new EKeyMap(); + (*map)->fParent = parent; + (*map)->AddKey(k); + } else { + KeySel ks; + + ParseKey(p, ks); + if ((k = (*map)->FindKey(ks.Key)) == 0) { // check if key exists + // add it if not + k = new EKey(p, 0); + (*map)->AddKey(k); + } + } + map = &k->fKeyMap; // set current map to key's map + + // get parent keymap + pm = parent; + parent = 0; + // printf("Searching %s\n", p); + while (pm) { // while exists + KeySel ks; + EKey *pk; + + ParseKey(p, ks); + if ((pk = pm->FindKey(ks.Key)) != 0) { // if key exists, find parent of it + parent = pk->fKeyMap; + // printf("Key found %d\n", parent); + break; + } + pm = pm->fParent; // otherwise find parent of current keymap + } + } + } + return 0; +} + +void InitWordChars() { + static int init = 0; + if (init == 0) { + for (int i = 0; i < 256; i++) + // isalnum??? + if (isdigit(i) || (i >= 'A' && i <= 'Z') + || (i >= 'a' && i <= 'z') || (i == '_')) { + WSETBIT(DefaultBufferFlags.WordChars, i, 1); + if ((i >= 'A' && i <= 'Z')) + WSETBIT(DefaultBufferFlags.CapitalChars, i, 1); + } + init = 1; + } +} + +void SetWordChars(char *w, const char *s) { + const char *p; + memset((void *)w, 0, 32); + + p = s; + while (p && *p) { + if (*p == '\\') { + p++; + if (*p == 0) return; + } else if (p[1] == '-') { + if (p[2] == 0) return ; + for (int i = p[0]; i < p[2]; i++) + WSETBIT(w, i, 1); + p += 2; + } + WSETBIT(w, *p, 1); + p++; + } +} + +EMode::EMode(EMode *aMode, EEventMap *Map, const char *aName) { + fNext = 0; + fName = strdup(aName); + fEventMap = Map; + fParent = aMode; + InitWordChars(); + if (aMode) { +#ifdef CONFIG_SYNTAX_HILIT + fColorize = aMode->fColorize; +#endif + Flags = aMode->Flags; + + // duplicate strings in flags to allow them be freed + for (int i=0; iFlags.str[i] != 0) + Flags.str[i] = strdup(aMode->Flags.str[i]); + } + + MatchName = 0; + MatchLine = 0; + MatchNameRx = 0; + MatchLineRx = 0; + if (aMode->MatchName) { + MatchName = strdup(aMode->MatchName); + MatchNameRx = RxCompile(MatchName); + } + if (aMode->MatchLine) { + MatchLine = strdup(aMode->MatchLine); + MatchLineRx = RxCompile(MatchLine); + } + } else { + MatchName = 0; + MatchLine = 0; + MatchNameRx = 0; + MatchLineRx = 0; +#ifdef CONFIG_SYNTAX_HILIT + fColorize = 0; +#endif + Flags = DefaultBufferFlags; + + // there is no strings in default settings... + } +} + +EMode::~EMode() { + + // fEventMap is just pointer to EventMaps list, so do not destroy it + // fColorize is also just a pointer + + free(fName); + + free(MatchName); + RxFree(MatchNameRx); + + free(MatchLine); + RxFree(MatchLineRx); + + // free strings from flags + for (int i=0; ifNext; + delete e; + } + } +} + +void EKeyMap::AddKey(EKey *aKey) { + aKey->fNext = fKeys; + fKeys = aKey; +} + + +int MatchKey(TKeyCode aKey, KeySel aSel) { + long flags = aKey & ~ 0xFFFF; + long key = aKey & 0xFFFF; + + flags &= ~kfAltXXX; + + if (flags & kfShift) { + if (key < 256) + if (flags == kfShift) + flags &= ~kfShift; + else if (isascii(key)) + key = toupper(key); + } + if ((flags & kfCtrl) && !(flags & kfSpecial)) + if (key < 32) + key += 64; + + flags &= ~aSel.Mask; + + if (aSel.Mask & kfShift) { + if (key < 256) + if (isascii(key)) + key = toupper(key); + } + aKey = key | flags; + if (aKey == aSel.Key) + return 1; + return 0; +} + +EKey *EKeyMap::FindKey(TKeyCode aKey) { + EKey *p = fKeys; + + while (p) { + if (MatchKey(aKey, p->fKey)) return p; + p = p->fNext; + } + return 0; +} + +EEventMap::EEventMap(const char *AName, EEventMap *AParent) { + Name = strdup(AName); + Parent = AParent; + KeyMap = 0; + Next = EventMaps; + EventMaps = this; + memset(Menu, 0, sizeof(Menu)); + memset(abbrev, 0, sizeof(abbrev)); +} + +EEventMap::~EEventMap() { + free(Name); + + // free menu[] + { + for (int i = 0; i < EM_MENUS; i++) + { + free(Menu[i]); + } + } + + // free Abbrev's + { + EAbbrev *ab; + + for (int i = 0; i < ABBREV_HASH; i++) + { + while((ab = abbrev[i]) != NULL) + { + abbrev[i] = abbrev[i]->next; + delete ab; + } + } + } + + // free keymap's + { + delete KeyMap; + } + +} + +void EEventMap::SetMenu(int which, const char *What) { + if (which < 0 || which >= EM_MENUS) + return; + if (Menu[which] != 0) + free(Menu[which]); + Menu[which] = strdup(What); +} + +char *EEventMap::GetMenu(int which) { + if (which < 0 || which >= EM_MENUS) + return 0; + if (Menu[which] || Parent == 0) + return Menu[which]; + else + return Parent->GetMenu(which); +} + +#ifdef CONFIG_ABBREV +int EEventMap::AddAbbrev(EAbbrev *ab) { + int i = HashStr(ab->Match, ABBREV_HASH); + ab->next = abbrev[i]; + abbrev[i] = ab; + return 1; +} + +EAbbrev *EMode::FindAbbrev(const char *string) { + EEventMap *Map = fEventMap; + EAbbrev *ab; + int i; + + if (string == 0) + return 0; + i = HashStr(string, ABBREV_HASH); + while (Map) { + ab = Map->abbrev[i]; + while (ab != 0) { + if (ab->Match && (strcmp(string, ab->Match) == 0)) + return ab; + ab = ab->next; + } + Map = Map->Parent; + } + return 0; +} +#endif + +static const struct { + const char *Name; + TKeyCode Key; +} KeyList[] = { + { "Esc", kbEsc }, + { "Tab", kbTab }, + { "Space", kbSpace }, + { "Enter", kbEnter }, + { "BackSp", kbBackSp }, + { "F1", kbF1 }, + { "F2", kbF2 }, + { "F3", kbF3 }, + { "F4", kbF4 }, + { "F5", kbF5 }, + { "F6", kbF6 }, + { "F7", kbF7 }, + { "F8", kbF8 }, + { "F9", kbF9 }, + { "F10", kbF10 }, + { "F11", kbF11 }, + { "F12", kbF12 }, + { "Left", kbLeft }, + { "Right", kbRight }, + { "Up", kbUp }, + { "Down", kbDown }, + { "Home", kbHome }, + { "End", kbEnd }, + { "PgUp", kbPgUp }, + { "PgDn", kbPgDn }, + { "Ins", kbIns }, + { "Del", kbDel }, + { "Center", kbCenter }, + { "Break", kbBreak }, + { "Pause", kbPause }, + { "PrtScr", kbPrtScr }, + { "SysReq", kbSysReq }, +}; + +int ParseKey(const char *Key, KeySel &ks) { + unsigned char *p = (unsigned char *)Key; + TKeyCode KeyFlags = 0; + int i; + + ks.Mask = 0; + ks.Key = 0; + while ((*p) && ((p[1] == '+') || (p[1] == '-'))) { + if (p[1] == '-') { + switch (p[0]) { + case 'A': ks.Mask |= kfAlt; break; + case 'C': ks.Mask |= kfCtrl; break; + case 'S': ks.Mask |= kfShift; break; + case 'G': ks.Mask |= kfGray; break; + case 'X': ks.Mask |= kfSpecial; break; + } + } else if (p[1] == '+') { + switch (p[0]) { + case 'A': KeyFlags |= kfAlt; break; + case 'C': KeyFlags |= kfCtrl; break; + case 'S': KeyFlags |= kfShift; break; + case 'G': KeyFlags |= kfGray; break; + case 'X': KeyFlags |= kfSpecial; break; + } + } + p += 2; + } + for (i = 0; i < int(sizeof(KeyList)/sizeof(KeyList[0])); i++) + if (strcmp((char *)p, KeyList[i].Name) == 0) { + ks.Key = KeyList[i].Key; + break; + } + if (ks.Key == 0) + ks.Key = *p; + if ((KeyFlags & kfCtrl) && !(KeyFlags & kfSpecial)) { + if (ks.Key < 256) { + if (ks.Key < 32) + ks.Key += 64; + else + ks.Key = toupper(ks.Key); + } + } + ks.Key |= KeyFlags; + return 0; +} + +int GetKeyName(char *Key, KeySel &ks) { + *Key = 0; + + if (ks.Key & kfAlt) strcat(Key, "A+"); + if (ks.Mask & kfAlt) strcat(Key, "A-"); + if (ks.Key & kfCtrl) strcat(Key, "C+"); + if (ks.Mask & kfCtrl) strcat(Key, "C-"); + if (ks.Key & kfGray) strcat(Key, "G+"); + if (ks.Mask & kfGray) strcat(Key, "G-"); + if (ks.Key & kfShift) strcat(Key, "S+"); + if (ks.Mask & kfShift) strcat(Key, "S-"); + + if (keyCode(ks.Key) < 256) { + char c[2]; + + c[0] = (char)(ks.Key & 0xFF); + c[1] = 0; + + //if (ks.Key & kfCtrl) + // if (c[0] < ' ') + // c[0] += '@'; + if (c[0] == 32) + strcat(Key, "Space"); + else + strcat(Key, c); + } else { + for (int i = 0; i < int(sizeof(KeyList)/sizeof(KeyList[0])); i++) + if (KeyList[i].Key == keyCode(ks.Key)) { + strcat(Key, KeyList[i].Name); + break; + } + } + return 0; +} + +EKey::EKey(char *aKey) { + fNext = 0; + ParseKey(aKey, fKey); + fKeyMap = 0; + Cmd = -1; +} + +EKey::EKey(char *aKey, EKeyMap *aKeyMap) { + fNext = 0; + Cmd = -1; + ParseKey(aKey, fKey); + fKeyMap = aKeyMap; +} + +EKey::~EKey() +{ + // if there is child keymaps delete them + delete fKeyMap; +} + +#ifdef CONFIG_ABBREV +EAbbrev::EAbbrev(const char *aMatch, const char *aReplace) { + next = 0; + Match = strdup(aMatch); + Replace = strdup(aReplace); + Cmd = -1; +} + +EAbbrev::EAbbrev(const char *aMatch, int aCmd) { + next = 0; + Replace = 0; + Match = strdup(aMatch); + Cmd = aCmd; +} + +EAbbrev::~EAbbrev() { + if (Match) + free(Match); + if (Replace) + free(Replace); +} +#endif + +int AddCommand(int no, int Command, int count, int ign) { + if (count == 0) return 0; + if (Command == 0) return 0; + Macros[no].cmds = (CommandType *)realloc(Macros[no].cmds, sizeof(CommandType) * (Macros[no].Count + 1)); + Macros[no].cmds[Macros[no].Count].type = CT_COMMAND; + Macros[no].cmds[Macros[no].Count].u.num = Command; + Macros[no].cmds[Macros[no].Count].repeat = short(count); + Macros[no].cmds[Macros[no].Count].ign = short(ign); + Macros[no].Count++; + return 1; +} + +int AddString(int no, const char *String) { + Macros[no].cmds = (CommandType *)realloc(Macros[no].cmds, sizeof(CommandType) * (Macros[no].Count + 1)); + Macros[no].cmds[Macros[no].Count].type = CT_STRING; + Macros[no].cmds[Macros[no].Count].u.string = strdup(String); + Macros[no].cmds[Macros[no].Count].repeat = 0; + Macros[no].cmds[Macros[no].Count].ign = 0; + Macros[no].Count++; + return 1; +} + +int AddNumber(int no, long number) { + Macros[no].cmds = (CommandType *)realloc(Macros[no].cmds, sizeof(CommandType) * (Macros[no].Count + 1)); + Macros[no].cmds[Macros[no].Count].type = CT_NUMBER; + Macros[no].cmds[Macros[no].Count].u.num = number; + Macros[no].cmds[Macros[no].Count].repeat = 0; + Macros[no].cmds[Macros[no].Count].ign = 0; + Macros[no].Count++; + return 1; +} + +int AddConcat(int no) { + Macros[no].cmds = (CommandType *)realloc(Macros[no].cmds, sizeof(CommandType) * (Macros[no].Count + 1)); + Macros[no].cmds[Macros[no].Count].type = CT_CONCAT; + Macros[no].cmds[Macros[no].Count].u.num = 0; + Macros[no].cmds[Macros[no].Count].repeat = 0; + Macros[no].cmds[Macros[no].Count].ign = 0; + Macros[no].Count++; + return 1; +} + +int AddVariable(int no, int number) { + Macros[no].cmds = (CommandType *)realloc(Macros[no].cmds, sizeof(CommandType) * (Macros[no].Count + 1)); + Macros[no].cmds[Macros[no].Count].type = CT_VARIABLE; + Macros[no].cmds[Macros[no].Count].u.num = number; + Macros[no].cmds[Macros[no].Count].repeat = 0; + Macros[no].cmds[Macros[no].Count].ign = 0; + Macros[no].Count++; + return 1; +} + +int NewCommand(const char *Name) { + Macros = (ExMacro *) realloc(Macros, sizeof(ExMacro) * (1 + CMacros)); + Macros[CMacros].Count = 0; + Macros[CMacros].cmds = 0; + Macros[CMacros].Name = (Name != NULL) ? strdup(Name) : 0; + CMacros++; + return CMacros - 1; +} + +int ExState::GetStrParam(EView *view, char *str, int maxlen) { + assert(maxlen >= 0); + if (Macro == -1 + || Pos == -1 + || Pos >= Macros[Macro].Count) + return 0; + if (Macros[Macro].cmds[Pos].type == CT_STRING) { + if (maxlen > 0) { + strncpy(str, Macros[Macro].cmds[Pos].u.string, maxlen); + str[maxlen - 1] = 0; + } + Pos++; + } else if (view && Macros[Macro].cmds[Pos].type == CT_VARIABLE) { + //puts("variable\x7"); + if (view->GetStrVar(Macros[Macro].cmds[Pos].u.num, str, maxlen) == 0) + return 0; + Pos++; + } else + return 0; + if (Pos < Macros[Macro].Count) { + if (Macros[Macro].cmds[Pos].type == CT_CONCAT) { + Pos++; + int len = strlen(str); + int left = maxlen - len; + + assert(left >= 0); + + //puts("concat\x7"); + if (GetStrParam(view, str + len, left) == 0) + return 0; + } + } + return 1; +} + +int ExState::GetIntParam(EView *view, int *value) { + if (Macro == -1 + || Pos == -1 + || Pos >= Macros[Macro].Count) + return 0; + if (Macros[Macro].cmds[Pos].type == CT_NUMBER) { + *value = Macros[Macro].cmds[Pos].u.num; + Pos++; + } else if (view && Macros[Macro].cmds[Pos].type == CT_VARIABLE) { + if (view->GetIntVar(Macros[Macro].cmds[Pos].u.num, value) == 0) + return 0; + Pos++; + } else + return 0; + return 1; +} + +int HashStr(const char *p, int maxim) { + unsigned int i = 1; + + while (p && *p) { + i += i ^ (i << 3) ^ (unsigned int)(*p) ^ (i >> 3); + p++; + } + return i % maxim; +} diff --git a/src/c_bind.h b/src/c_bind.h new file mode 100644 index 0000000..3c866fd --- /dev/null +++ b/src/c_bind.h @@ -0,0 +1,166 @@ +/* c_bind.h + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#ifndef __BIND_H +#define __BIND_H + +#define ABBREV_HASH 16 + +class EMode; +class EEventMap; +class EKeyMap; +class EKey; +class EAbbrev; +class EView; + +typedef struct { + TKeyCode Mask; + TKeyCode Key; +} KeySel; + +class EMode { +public: + EMode *fNext; + char *fName; + char *MatchName; + char *MatchLine; + RxNode *MatchNameRx; + RxNode *MatchLineRx; + EBufferFlags Flags; + EEventMap *fEventMap; + EMode *fParent; +#ifdef CONFIG_SYNTAX_HILIT + EColorize *fColorize; +#endif + char filename[256]; + + EMode(EMode *aMode, EEventMap *Map, const char *aName); + ~EMode(); + EAbbrev *FindAbbrev(const char *string); +}; + +class EKeyMap { +public: + EKeyMap *fParent; + EKey *fKeys; + + EKeyMap(); + ~EKeyMap(); + + void AddKey(EKey *aKey); + EKey *FindKey(TKeyCode aKey); +}; + +class EEventMap { +public: + EEventMap *Next; + EEventMap *Parent; + char *Name; + + EKeyMap *KeyMap; + char *Menu[EM_MENUS]; // main + local + + EAbbrev *abbrev[ABBREV_HASH]; + + EEventMap(const char *AName, EEventMap *AParent); + ~EEventMap(); + void SetMenu(int which, const char *What); + char *GetMenu(int which); +#ifdef CONFIG_ABBREV + int AddAbbrev(EAbbrev *ab); +#endif +}; + +#define CT_COMMAND 0 +#define CT_NUMBER 1 +#define CT_STRING 2 +#define CT_VARIABLE 3 +#define CT_CONCAT 4 /* concatenate strings */ + +typedef struct { + int type; + short repeat; + short ign; + union { + long num; + char *string; + } u; +} CommandType; + +typedef struct { + char *Name; + int Count; + CommandType *cmds; +} ExMacro; + +class EKey { +public: + KeySel fKey; + int Cmd; + EKeyMap *fKeyMap; + EKey *fNext; + + EKey(char *aKey); + EKey(char *aKey, EKeyMap *aKeyMap); + ~EKey(); +}; + +#ifdef CONFIG_ABBREV +class EAbbrev { +public: + EAbbrev *next; + int Cmd; + char *Match; + char *Replace; + + EAbbrev(const char *aMatch, const char *aReplace); + EAbbrev(const char *aMatch, int aCmd); + ~EAbbrev(); +}; +#endif + +class ExState { // state of macro execution +public: + int Macro; + int Pos; + + int GetStrParam(EView *view, char *str, int buflen); + int GetIntParam(EView *view, int *value); +}; + +extern EMode *Modes; +extern EEventMap *EventMaps; + +extern int CMacros; +extern ExMacro *Macros; + +int GetCharFromEvent(TEvent &E, char *Ch); + +const char *GetCommandName(int Command); +EMode *FindMode(const char *Name); +EEventMap *FindEventMap(const char *Name); +EEventMap *FindActiveMap(EMode *Mode); +EMode *GetModeForName(const char *FileName); +int CmdNum(const char *Cmd); +void ExecKey(EKey *Key); +EKey *SetKey(EEventMap *aMap, const char *Key); +int ParseKey(const char *Key, KeySel &ks); +int GetKeyName(char *Key, KeySel &ks); + +int NewCommand(const char *Name); +int RunCommand(int Command); +int AddCommand(int no, int cmd, int count, int ign); +int AddString(int no, const char *Command); +int AddNumber(int no, long number); +int AddVariable(int no, int number); +int AddConcat(int no); +int HashStr(const char *str, int maxim); +void SetWordChars(char *w, const char *s); + +#endif diff --git a/src/c_cmdtab.h b/src/c_cmdtab.h new file mode 100644 index 0000000..83dd0a1 --- /dev/null +++ b/src/c_cmdtab.h @@ -0,0 +1,335 @@ +/* c_cmdtab.h + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#define TAB(x) \ + { Ex##x, #x } + +const struct { + unsigned short CmdId; + const char *Name; +} Command_Table[] = { +TAB(Nop), +TAB(Fail), +TAB(MoveLeft), +TAB(MoveRight), +TAB(MoveUp), +TAB(MoveDown), +TAB(MovePrev), +TAB(MoveNext), +TAB(MoveWordLeft), +TAB(MoveWordRight), +TAB(MoveWordPrev), +TAB(MoveWordNext), +TAB(MoveWordEndLeft), +TAB(MoveWordEndRight), +TAB(MoveWordEndPrev), +TAB(MoveWordEndNext), +TAB(MoveWordOrCapLeft), +TAB(MoveWordOrCapRight), +TAB(MoveWordOrCapPrev), +TAB(MoveWordOrCapNext), +TAB(MoveWordOrCapEndLeft), +TAB(MoveWordOrCapEndRight), +TAB(MoveWordOrCapEndPrev), +TAB(MoveWordOrCapEndNext), +TAB(MoveLineStart), +TAB(MoveLineEnd), +TAB(MovePageUp), +TAB(MovePageDown), +TAB(MovePageLeft), +TAB(MovePageRight), +TAB(MovePageStart), +TAB(MovePageEnd), +TAB(MoveFileStart), +TAB(MoveFileEnd), +TAB(MoveBlockStart), +TAB(MoveBlockEnd), +TAB(MoveFirstNonWhite), +TAB(MoveLastNonWhite), +TAB(MovePrevEqualIndent), +TAB(MoveNextEqualIndent), +TAB(MovePrevTab), +TAB(MoveNextTab), +TAB(MoveLineTop), +TAB(MoveLineCenter), +TAB(MoveLineBottom), +TAB(ScrollLeft), +TAB(ScrollRight), +TAB(ScrollDown), +TAB(ScrollUp), +TAB(MoveTabStart), +TAB(MoveTabEnd), + +TAB(KillLine), +TAB(KillChar), +TAB(KillCharPrev), +TAB(KillWord), +TAB(KillWordPrev), +TAB(KillWordOrCap), +TAB(KillWordOrCapPrev), +TAB(KillToLineStart), +TAB(KillToLineEnd), +TAB(KillBlock), +TAB(KillBlockOrChar), +TAB(KillBlockOrCharPrev), +TAB(BackSpace), +TAB(Delete), +TAB(CharCaseUp), +TAB(CharCaseDown), +TAB(CharCaseToggle), +TAB(LineCaseUp), +TAB(LineCaseDown), +TAB(LineCaseToggle), +TAB(LineInsert), +TAB(LineAdd), +TAB(LineSplit), +TAB(LineJoin), +TAB(LineNew), +TAB(LineIndent), +TAB(LineTrim), +TAB(FileTrim), +TAB(BlockTrim), + +TAB(InsertSpacesToTab), +TAB(InsertTab), +TAB(InsertSpace), +TAB(WrapPara), +TAB(InsPrevLineChar), +TAB(InsPrevLineToEol), +TAB(LineDuplicate), +TAB(BlockBegin), +TAB(BlockEnd), +TAB(BlockUnmark), +TAB(BlockCut), +TAB(BlockCopy), +TAB(BlockCutAppend), +TAB(BlockCopyAppend), +TAB(ClipClear), +TAB(BlockPaste), +TAB(BlockKill), +TAB(BlockSort), +TAB(BlockSortReverse), +TAB(BlockIndent), +TAB(BlockUnindent), +TAB(BlockClear), +TAB(BlockMarkStream), +TAB(BlockMarkLine), +TAB(BlockMarkColumn), +TAB(BlockCaseUp), +TAB(BlockCaseDown), +TAB(BlockCaseToggle), +TAB(BlockExtendBegin), +TAB(BlockExtendEnd), +TAB(BlockReIndent), +TAB(BlockSelectWord), +TAB(BlockSelectLine), +TAB(BlockSelectPara), +TAB(Undo), +TAB(Redo), +TAB(MatchBracket), +TAB(MovePrevPos), +TAB(MoveSavedPosCol), +TAB(MoveSavedPosRow), +TAB(MoveSavedPos), +TAB(SavePos), +TAB(CompleteWord), +TAB(MoveToLine), +TAB(MoveToColumn), +TAB(BlockPasteStream), +TAB(BlockPasteLine), +TAB(BlockPasteColumn), +TAB(ShowPosition), + +TAB(FoldCreate), +TAB(FoldCreateByRegexp), +TAB(FoldDestroy), +TAB(FoldDestroyAll), +TAB(FoldPromote), +TAB(FoldDemote), +TAB(FoldOpen), +TAB(FoldOpenNested), +TAB(FoldClose), +TAB(FoldOpenAll), +TAB(FoldCloseAll), +TAB(FoldToggleOpenClose), +TAB(MoveFoldTop), +TAB(MoveFoldPrev), +TAB(MoveFoldNext), + +TAB(PlaceBookmark), +TAB(RemoveBookmark), +TAB(GotoBookmark), + +TAB(InsertString), +TAB(SelfInsert), +TAB(FilePrev), +TAB(FileNext), +TAB(FileLast), +TAB(SwitchTo), + +TAB(FileReload), +TAB(FileSave), +TAB(FileSaveAll), +TAB(FileSaveAs), +TAB(FileWriteTo), +TAB(FileOpen), +TAB(FileOpenInMode), +TAB(FilePrint), + +TAB(BlockPrint), +TAB(BlockRead), +TAB(BlockReadStream), +TAB(BlockReadLine), +TAB(BlockReadColumn), +TAB(BlockWrite), + +TAB(IncrementalSearch), +TAB(Find), +TAB(FindReplace), +TAB(FindRepeat), +TAB(FindRepeatOnce), +TAB(FindRepeatReverse), + +TAB(InsertChar), + +TAB(FileClose), +TAB(FileCloseAll), + +TAB(WinRefresh), + +TAB(WinHSplit), +TAB(WinNext), +TAB(WinPrev), +TAB(WinClose), +TAB(WinZoom), +TAB(WinResize), + +TAB(ExitEditor), + +TAB(ViewBuffers), +TAB(ListRoutines), +TAB(DirOpen), + +TAB(Compile), +TAB(CompilePrevError), +TAB(CompileNextError), +TAB(ViewMessages), + +TAB(ShowKey), +TAB(ShowEntryScreen), +TAB(RunProgram), +TAB(HilitWord), +TAB(SearchWordPrev), +TAB(SearchWordNext), +TAB(HilitMatchBracket), +TAB(MainMenu), +TAB(LocalMenu), +TAB(ShowMenu), +TAB(ChangeMode), +TAB(ChangeKeys), +TAB(ChangeFlags), + +TAB(ToggleAutoIndent), +TAB(ToggleInsert), +TAB(ToggleExpandTabs), +TAB(ToggleShowTabs), +TAB(ToggleUndo), +TAB(ToggleReadOnly), +TAB(ToggleKeepBackups), +TAB(ToggleMatchCase), +TAB(ToggleBackSpKillTab), +TAB(ToggleDeleteKillTab), +TAB(ToggleSpaceTabs), +TAB(ToggleIndentWithTabs), +TAB(ToggleBackSpUnindents), +TAB(ToggleWordWrap), +TAB(ToggleTrim), +TAB(ToggleShowMarkers), +TAB(SetLeftMargin), +TAB(SetRightMargin), +TAB(SetPrintDevice), +TAB(ChangeTabSize), +TAB(ChangeLeftMargin), +TAB(ChangeRightMargin), +TAB(ToggleSysClipboard), +TAB(Cancel), +TAB(Activate), +TAB(Rescan), +TAB(CloseActivate), +TAB(ActivateInOtherWindow), +TAB(DirGoUp), +TAB(DirGoDown), +TAB(DirGoRoot), +TAB(DirGoto), +TAB(DeleteFile), +TAB(ShowVersion), +TAB(ASCIITable), +TAB(TypeChar), +TAB(CharTrans), +TAB(LineTrans), +TAB(BlockTrans), +TAB(DesktopSave), +TAB(DesktopSaveAs), +TAB(ChildClose), +TAB(BufListFileSave), +TAB(BufListFileClose), +TAB(ViewModeMap), +TAB(ClearMessages), +TAB(BlockUnTab), +TAB(BlockEnTab), +TAB(TagFind), +TAB(TagFindWord), +TAB(TagNext), +TAB(TagPrev), +TAB(TagPop), +TAB(TagLoad), +TAB(TagClear), +TAB(TagGoto), +TAB(BlockMarkFunction), +TAB(IndentFunction), +TAB(MoveFunctionPrev), +TAB(MoveFunctionNext), +TAB(Search), +TAB(SearchB), +TAB(SearchRx), +TAB(SearchAgain), +TAB(SearchAgainB), +TAB(SearchReplace), +TAB(SearchReplaceB), +TAB(SearchReplaceRx), +TAB(InsertDate), +TAB(InsertUid), +TAB(FrameNew), +TAB(FrameClose), +TAB(FrameNext), +TAB(FramePrev), +TAB(ShowHelpWord), +TAB(ShowHelp), +TAB(ConfigRecompile), +TAB(PlaceGlobalBookmark), +TAB(RemoveGlobalBookmark), +TAB(GotoGlobalBookmark), +TAB(MoveBeginOrNonWhite), +TAB(MoveBeginLinePageFile), +TAB(MoveEndLinePageFile), +TAB(PushGlobalBookmark), +TAB(PopGlobalBookmark), +TAB(SetCIndentStyle), +TAB(SetIndentWithTabs), +TAB(RunCompiler), +TAB(FoldCreateAtRoutines), +TAB(LineCenter), +TAB(RunProgramAsync) +#if 0 +//TAB(ShowMsg), +TAB(BlockReadPipe), +TAB(BlockWritePipe), +TAB(BlockPipe), +#endif +}; diff --git a/src/c_color.cpp b/src/c_color.cpp new file mode 100644 index 0000000..e66bd1d --- /dev/null +++ b/src/c_color.cpp @@ -0,0 +1,129 @@ +/* c_color.cpp + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#include "fte.h" + +ChColor MsgColor[3] = { 0x07, 0x0B, 0x04 }; + +/* Status line */ + +ChColor hcStatus_Normal = 0x30; +ChColor hcStatus_Active = 0x70; + +ChColor hcEntry_Field = 0x07; +ChColor hcEntry_Prompt = 0x0F; +ChColor hcEntry_Selection = 0x2F; + +/* Plain */ + +ChColor hcPlain_Normal = 0x07; +ChColor hcPlain_Background = 0x07; +ChColor hcPlain_Selected = 0x80; +ChColor hcPlain_Markers = 0x03; +ChColor hcPlain_Found = 0x40; +ChColor hcPlain_Keyword = 0x0F; +ChColor hcPlain_Folds = 0x0A; +ChColor hcPlain_HilitWord = 0x0D; + +/* LIST */ +//ChColor hcList_Border = 0x03; +ChColor hcList_Status = 0x70; +ChColor hcList_Normal = 0x07; +ChColor hcList_Selected = 0x1F; + +ChColor hcScrollBar_Arrows = 0x70; +ChColor hcScrollBar_Back = 0x07; +ChColor hcScrollBar_Fore = 0x07; + +ChColor hcAsciiChars = 0x07; + +ChColor hcMenu_Background = 0x70; +ChColor hcMenu_ActiveItem = 0x1F; +ChColor hcMenu_ActiveChar = 0x1C; +ChColor hcMenu_NormalItem = 0x70; +ChColor hcMenu_NormalChar = 0x74; + +ChColor hcChoice_Title = 0x1F; +ChColor hcChoice_Param = 0x1B; +ChColor hcChoice_Background = 0x17; +ChColor hcChoice_ActiveItem = 0x20; +ChColor hcChoice_ActiveChar = 0x2F; +ChColor hcChoice_NormalItem = 0x1F; +ChColor hcChoice_NormalChar = 0x1E; + +static const struct { + const char *Name; + ChColor *C; +} Colors[] = +{ + { "Status.Normal", &hcStatus_Normal }, + { "Status.Active", &hcStatus_Active }, + + { "Message.Normal", &MsgColor[0] }, + { "Message.Bold", &MsgColor[1] }, + { "Message.Error", &MsgColor[2] }, + + { "Entry.Field", &hcEntry_Field }, + { "Entry.Prompt", &hcEntry_Prompt }, + { "Entry.Selection", &hcEntry_Selection }, + + { "LIST.Status", &hcList_Status }, + { "LIST.Normal", &hcList_Normal }, + { "LIST.Selected", &hcList_Selected }, + + { "PLAIN.Normal", &hcPlain_Normal }, + { "PLAIN.Background", &hcPlain_Background }, + { "PLAIN.Selected", &hcPlain_Selected }, + { "PLAIN.Markers", &hcPlain_Markers }, + { "PLAIN.Found", &hcPlain_Found }, + { "PLAIN.Keyword", &hcPlain_Keyword }, + { "PLAIN.Folds", &hcPlain_Folds }, + { "PLAIN.HilitWord", &hcPlain_HilitWord }, + + { "ScrollBar.Arrows", &hcScrollBar_Arrows }, + { "ScrollBar.Back", &hcScrollBar_Back }, + { "ScrollBar.Fore", &hcScrollBar_Fore }, + + { "ASCII.Chars", &hcAsciiChars }, + + { "Menu.Background", &hcMenu_Background }, + { "Menu.ActiveItem", &hcMenu_ActiveItem }, + { "Menu.ActiveChar", &hcMenu_ActiveChar }, + { "Menu.NormalItem", &hcMenu_NormalItem }, + { "Menu.NormalChar", &hcMenu_NormalChar }, + + { "Choice.Title", &hcChoice_Title }, + { "Choice.Param", &hcChoice_Param }, + { "Choice.Background", &hcChoice_Background }, + { "Choice.ActiveItem", &hcChoice_ActiveItem }, + { "Choice.ActiveChar", &hcChoice_ActiveChar }, + { "Choice.NormalItem", &hcChoice_NormalItem }, + { "Choice.NormalChar", &hcChoice_NormalChar }, +}; +#define NCOLORS (sizeof(Colors)/sizeof(Colors[0])) + +int SetColor(const char *ColorV, const char *Value) { + unsigned int Col; + unsigned int ColBg, ColFg; + ChColor C; + + if (sscanf(Value, "%1X %1X", &ColFg, &ColBg) != 2) + return 0; + + Col = ColFg | (ColBg << 4); + + C = ChColor(Col); + for (unsigned int i = 0; i < NCOLORS; i++) { + if (strcmp(ColorV, Colors[i].Name) == 0) { + *Colors[i].C = C; + return 1; + } + } + return 0; +} diff --git a/src/c_color.h b/src/c_color.h new file mode 100644 index 0000000..d43ede6 --- /dev/null +++ b/src/c_color.h @@ -0,0 +1,58 @@ +/* c_color.h + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#ifndef __COLOR_H +#define __COLOR_H + +extern ChColor hcStatus_Normal; +extern ChColor hcStatus_Active; + +extern ChColor hcPlain_Normal; +extern ChColor hcPlain_Background; +extern ChColor hcPlain_Selected; +extern ChColor hcPlain_Markers; +extern ChColor hcPlain_Found; +extern ChColor hcPlain_Keyword; +extern ChColor hcPlain_Folds; +extern ChColor hcPlain_HilitWord; + +extern ChColor hcEntry_Field; +extern ChColor hcEntry_Prompt; +extern ChColor hcEntry_Selection; + +//extern ChColor hcList_Border; +extern ChColor hcList_Status; +extern ChColor hcList_Normal; +extern ChColor hcList_Selected; + +extern ChColor hcScrollBar_Arrows; +extern ChColor hcScrollBar_Back; +extern ChColor hcScrollBar_Fore; + +extern ChColor hcAsciiChars; + +extern ChColor hcMenu_Background; +extern ChColor hcMenu_ActiveItem; +extern ChColor hcMenu_ActiveChar; +extern ChColor hcMenu_NormalItem; +extern ChColor hcMenu_NormalChar; + +extern ChColor hcChoice_Title; +extern ChColor hcChoice_Param; +extern ChColor hcChoice_Background; +extern ChColor hcChoice_ActiveItem; +extern ChColor hcChoice_ActiveChar; +extern ChColor hcChoice_NormalItem; +extern ChColor hcChoice_NormalChar; + +extern ChColor MsgColor[3]; + +int SetColor(const char *ChColor, const char *Value); + +#endif diff --git a/src/c_commands.h b/src/c_commands.h new file mode 100644 index 0000000..69ef67c --- /dev/null +++ b/src/c_commands.h @@ -0,0 +1,698 @@ +/* c_commands.h + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#ifndef __COMMANDS_H__ +#define __COMMANDS_H__ + +typedef enum { + ErFAIL = 0, + ErOK = 1 +} ExResult; + +typedef enum { + ExNop, + ExFail, + + // Cursor Movement + + //& CursorTroughTabs + + ExMoveDown, + /// Move cursor to next line. + ExMoveUp, + /// Move cursor to previous line + ExMoveLeft, + /// Move cursor to previous column. + ExMoveRight, + /// Move cursor to next column. + ExMovePrev, + /// Move cursor to previous character. Moves to end of the previous + /// line if cursor is at the beginning of line. + ExMoveNext, + /// Move cursor to next character. Moves to the beginning of next + /// line if cursor is at the end of line. + ExMoveWordLeft, + /// Move cursor to the beginning of the word on the left. + ExMoveWordRight, + /// Move cursor to the beginning of the word on the right. + ExMoveWordPrev, + /// Move cursor to the beginning of the previous word. + ExMoveWordNext, + /// Move cursor to the beginning of the next word. + ExMoveWordEndLeft, + /// Move cursor to the end of the previous word. + ExMoveWordEndRight, + /// Move cursor to the end of the word on the right. + ExMoveWordEndPrev, + /// Move cursor to the end of the previous word. + ExMoveWordEndNext, + /// Move cursor to the end of the next word. + ExMoveWordOrCapLeft, + /// Move cursor to the beginning of the word or capital letter on the right. + ExMoveWordOrCapRight, + /// Move cursor to the beginning of the word or capital letter on the left. + ExMoveWordOrCapPrev, + /// Move cursor to the beginning of the previous word or to previous + /// capital letter. + ExMoveWordOrCapNext, + /// Move cursor to the beginning of the next word or to next capital letter. + ExMoveWordOrCapEndLeft, + /// Move cursor to the end of the word or capitals on the left. + ExMoveWordOrCapEndRight, + /// Move cursor to the end of the word or capitals on the right. + ExMoveWordOrCapEndPrev, + /// Move cursor to the end of the previous word or capitals. + ExMoveWordOrCapEndNext, + /// Move cursor to the end of the next word or capitals. + ExMoveLineStart, + /// Move cursor to the beginning of line. + ExMoveLineEnd, + /// Move cursor to the end of line. + ExMovePageStart, + /// Move cursor to the first line on current page. + ExMovePageEnd, + /// Move cursor to the last line on currently page. + ExMovePageUp, + /// Display previous page. + ExMovePageDown, + /// Display next page. + ExMoveFileStart, + /// Move cursor to the beginning of file. + ExMoveFileEnd, + /// Move cursor to the end of file. + ExMovePageLeft, + /// Scroll horizontally to display page on the left. + ExMovePageRight, + /// Scroll horizontally to display page on the right. + ExMoveBlockStart, + /// Move cursor to the beginning of block. + ExMoveBlockEnd, + /// Move cursor to end beginning of block. + ExMoveFirstNonWhite, + /// Move cursor to the first non-blank character on line. + ExMoveLastNonWhite, + /// Move cursor to the last non-blank character on line. + ExMovePrevEqualIndent, + /// Move cursor to the previous line with equal indentation. + ExMoveNextEqualIndent, + /// Move cursor to the next line with equal indentation. + ExMovePrevTab, + /// Move cursor to the previous tab position. + ExMoveNextTab, + /// Move cursor to the next tab position. + ExMoveTabStart, + /// When cursor is on the tab characters, moves it to the beginning + /// of the tab. + ExMoveTabEnd, + /// When cursor is on the tab characters, moves it to the end + /// of the tab. + ExMoveLineTop, + /// Scroll the file to make the current line appear on the top of the window. + ExMoveLineCenter, + /// Scroll the file to make the current line appear on the center of the window. + ExMoveLineBottom, + /// Scroll the file to make the current line appear on the bottom of the window. + ExScrollLeft, + /// Scroll screen left. + ExScrollRight, + /// Scroll screen right. + ExScrollDown, + /// Scroll screen down. + ExScrollUp, + /// Scroll screen up. + ExMoveFoldTop, + /// Move to the beginning of current fold. + ExMoveFoldPrev, + /// Move to the beginning of previous fold. + ExMoveFoldNext, + /// Move to the beginning of next fold. + ExMoveBeginOrNonWhite, + /// Move to beginning of line, or to first non blank character + ExMoveBeginLinePageFile, + /// Move to the beginning of line. If there already, move to the beginning + /// page. If there already, move to the beginning of file. + ExMoveEndLinePageFile, + /// Move to the end of line. If there already, move to the end + /// page. If there already, move to the end of file. + ExMoveToLine, + /// Move to line number given as argument + ExMoveToColumn, + /// Move to column given as argument + ExMoveSavedPosCol, + /// Move to column from saved position + ExMoveSavedPosRow, + /// Move to line from saved position + ExMoveSavedPos, + /// Move to saved position + ExSavePos, + /// Save current cursor position + ExMovePrevPos, + /// Move to last cursor position + // ExCursorPush, + // ExCursorPop, + + + // Deleting Text + ExKillLine, + /// Delete current line. If the line is the last line in the file, + /// only the text is deleted. + ExKillChar, + /// Delete character under (after) cursor. + ExKillCharPrev, + /// Delete character before cursor. + ExKillWord, + /// Delete the word after cursor. + ExKillWordPrev, + /// Delete the word before cursor. + ExKillWordOrCap, + /// Delete word or capitals after cursor. + ExKillWordOrCapPrev, + /// Delete word or capitals before cursor. + ExKillToLineStart, + /// Delete characters to the beginning of line. + ExKillToLineEnd, + /// Delete characters to the end of line. + ExKillBlock, + /// Delete block. + ExKillBlockOrChar, + /// If block is marked, delete it, otherwise delete character under cursor. + ExKillBlockOrCharPrev, + /// If block is marked, delete it, otherwise delete character before cursor. + ExDelete, + /// Delete character under (after) cursor. + //& DeleteKillTab + //& DeleteKillBlock + ExBackSpace, + /// Delete character before cursor. + //& BackSpKillTab + //& BackSpKillBlock + + // Line Commands + ExLineInsert, + /// Insert a new line before the current one. + ExLineAdd, + /// Add a new line after the current one. + ExLineSplit, + /// Split current line after cursor position + ExLineJoin, + /// Join current line with next one. If cursor is positioned beyond + /// the end of line, the current line is first padded with whitespace. + ExLineNew, + /// Append a new line and move to the beginning of new line. + ExLineIndent, + /// Reindent current line. + ExLineTrim, + /// Trim whitespace at the end of current line. + ExLineDuplicate, + /// Duplicate the current line. + ExLineCenter, + /// Center the current line + + // Block Commands + ExBlockBegin, + /// Set block beginning to current position. + ExBlockEnd, + /// Set block end to current position. + ExBlockUnmark, + /// Unmark block. + ExBlockCut, + /// Cut selected block to clipboard. + ExBlockCopy, + /// Copy selected block to clipboard. + ExBlockCutAppend, + /// Cut selected block and append it to clipboard. + ExBlockCopyAppend, + /// Append selected block to clipboard. + ExBlockClear, + /// Clear selected block + ExBlockPaste, + /// Paste clipboard to current position. + ExBlockKill, + /// Delete selected text. + ExBlockIndent, + /// Indent block by 1 character. + ExBlockUnindent, + /// Unindent block by 1 character. + ExBlockMarkStream, + /// Start/stop marking stream block. + ExBlockMarkLine, + /// Start/stop marking line block. + ExBlockMarkColumn, + /// Start/stop marking column block. + ExBlockExtendBegin, + /// Start extending selected block. + ExBlockExtendEnd, + /// Stop extending selected block. + ExBlockReIndent, + /// Reindent entire block (C/REXX mode) + ExBlockSelectWord, + /// Select word under cursor as block. + ExBlockSelectLine, + /// Select current line as block. + ExBlockSelectPara, + /// Select current paragraph (delimited by blank lines) as block. + ExBlockPasteStream, + /// Paste clipboard to current position as stream block. + ExBlockPasteLine, + /// Paste clipboard to current position as line block. + ExBlockPasteColumn, + /// Paste clipboard to current position as column block. + ExBlockPrint, + /// Print a block to configured device. + ExBlockRead, + /// Read block from file. + ExBlockReadStream, + /// Read block from file as stream block + ExBlockReadLine, + /// Read block from file as line block + ExBlockReadColumn, + /// Read block from file as column block + ExBlockWrite, + /// Write marked block to file. + ExBlockSort, + /// Sorts the marked block in ascending order. + /// + //\ If mode setting MatchCase is set, characters will be compared case + //\ sensitively. + /// + //\ When block is marked in + //\ Stream or Line mode, + //\ the entire lines in marked block will be compared. + /// + //\ When block is marked in Column + //\ mode, only characters within marked columns will be compared. + ExBlockSortReverse, + /// Sorts the marked block in descending order. + //^ BlockSort + ExBlockUnTab, + /// Remove tabs from marked lines. + ExBlockEnTab, + /// Generate and optimize tabs in marked lines. + ExBlockMarkFunction, + /// Mark current function as block. + ExBlockTrim, + /// Trim end-of-line whitespace + + // Text Editing and Insertion + ExUndo, + /// Undo last operation + ExRedo, + /// Redo last undone operation. + + // Folding Text + ExFoldCreate, + /// Create fold + ExFoldCreateByRegexp, + /// Create folds at lines matching a regular expression + ExFoldCreateAtRoutines, + /// Create folds at lines matching RoutineRx + ExFoldDestroy, + /// Destroy fold at current line + ExFoldDestroyAll, + /// Destroy all folds in the file + ExFoldPromote, + /// Promote fold to outer level + ExFoldDemote, + /// Demote fold to inner level + ExFoldOpen, + /// Open fold at current line + ExFoldOpenNested, + /// Open fold and nested folds + ExFoldClose, + /// Close current fold + ExFoldOpenAll, + /// Open all folds in the file + ExFoldCloseAll, + /// Close all folds in the file + ExFoldToggleOpenClose, + /// Toggle open/close current fold. + + //Bookmarks + ExPlaceBookmark, + /// Place a file-local bookmark. + ExRemoveBookmark, + /// Place a file-local bookmark. + ExGotoBookmark, + /// Go to file-local bookmark location. + ExPlaceGlobalBookmark, + /// Place global (persistent) bookmark. + ExRemoveGlobalBookmark, + /// Remove global bookmark. + ExGotoGlobalBookmark, + /// Go to global bookmark location. + ExPushGlobalBookmark, + /// Push global bookmark (named as #) to stack. + ExPopGlobalBookmark, + /// Pop global bookmark from stack. + + // Character Translation + ExCharCaseUp, + /// Convert current character to uppercase + ExCharCaseDown, + /// Convert current character to lowercase + ExCharCaseToggle, + /// Toggle case of current character + ExCharTrans, + /// Translate current character (like perl/sed) + ExLineCaseUp, + /// Convert current line to uppercase + ExLineCaseDown, + /// Convert current line to lowercase + ExLineCaseToggle, + /// Toggle case of current line + ExLineTrans, + /// Translate characters on current line + ExBlockCaseUp, + /// Convert characters in selected block to uppercase + ExBlockCaseDown, + /// Convert characters in selected block to lowercase + ExBlockCaseToggle, + /// Toggle case of characters in selected block + ExBlockTrans, + /// Translate characters in selected block. + + ExInsertString, + /// Insert argument string at cursor position + ExInsertSpace, + /// Insert space + ExInsertChar, + /// Insert character argument at cursor position + ExTypeChar, + /// Insert character at cursor position (expanding abbreviations) + ExInsertTab, + /// Insert tab character at cursor position + ExInsertSpacesToTab, + /// Insert appropriate number of spaces to simulate a tab. + ExSelfInsert, + /// Insert typed character + ExWrapPara, + /// Wrap current paragraph + ExInsPrevLineChar, + /// Insert character in previous line above cursor + ExInsPrevLineToEol, + /// Insert previous line from cursor to end of line + ExCompleteWord, + /// Complete current word to last word starting with the + /// same prefix. + + ExFilePrev, + /// Switch to previous file in ring. + ExFileNext, + /// Switch to next file in ring. + ExFileLast, + /// Exchange last two files in ring. + ExSwitchTo, + /// Switch to numbered buffer given as argument + + // File Commands + ExFileOpen, + /// Open file + ExFileOpenInMode, + /// Open file in specified mode + ExFileReload, + /// Reload current file + ExFileSave, + /// Save current file + ExFileSaveAll, + /// Save all modified files + ExFileSaveAs, + /// Rename Save current file + ExFileWriteTo, + /// Write current file into another file + ExFilePrint, + /// Print current file + ExFileClose, + /// Close current file + ExFileCloseAll, + /// Close all open files + ExFileTrim, + /// Trim end-of-line whitespace + + // + ExDirOpen, + /// Open directory browser + ExDirGoUp, + /// Change to parent directory + ExDirGoDown, + /// Change to currently selected directory + ExDirGoRoot, + /// Change to root directory + ExDirGoto, + /// Change to directory given as argument + + // + ExIncrementalSearch, + /// Incremental search + ExFind, + /// Find + ExFindReplace, + /// Find and replace + ExFindRepeat, + /// Repeat last find/replace operation + ExFindRepeatOnce, + /// Repeat last find/replace operation only once + ExFindRepeatReverse, + /// Repeat last find/replace operation in reverse + ExMatchBracket, + /// Find matching bracket ([{<>}]) + ExHilitWord, + /// Highlight current word everywhere in the file + ExSearchWordPrev, + /// Search for previous occurence of word under cursor + ExSearchWordNext, + /// Search for next occurence of word under cursor + ExHilitMatchBracket, + /// Highlight matching bracket + ExSearch, + ExSearchB, + ExSearchRx, + ExSearchAgain, + ExSearchAgainB, + ExSearchReplace, + ExSearchReplaceB, + ExSearchReplaceRx, + + // Window Commands + ExWinHSplit, + /// Split window horizontally + ExWinNext, + /// Switch to next (bottom) window + ExWinPrev, + /// Switcn to previous (top) window. + ExWinClose, + /// Close current window + ExWinZoom, + /// Delete all windows except for current one + ExWinResize, + /// Resize current window (+n,-n given as argument) + ExViewBuffers, + /// View currently open buffers + ExListRoutines, + /// Display routines in current source file + ExExitEditor, + /// Exit FTE. + ExShowEntryScreen, + /// View external program output if available + + // Compiler Support + ExCompile, + /// Ask for compile command and run compiler + ExRunCompiler, + /// Run configured compile command + ExViewMessages, + /// View compiler output + ExCompileNextError, + /// Switch to next compiler error + ExCompilePrevError, + /// Switch to previous compiler error + ExRunProgram, + /// Run external program + + // TAGS Commands + /// fte supports TAGS files generated by programs like ctags. + ExTagFind, + /// Find word argumen in tag files. + ExTagFindWord, + /// Find word under cursor in tag files. + ExTagNext, + /// Switch to next occurance of tag + ExTagPrev, + /// Switch to previous occurance of tag + ExTagPop, + /// Pop saved position from tag stack + ExTagLoad, + /// Load tag file and merge with current tags + ExTagClear, + /// Clear loaded tags + ExTagGoto, + /// + + // Option commands + ExToggleAutoIndent, + /// + ExToggleInsert, + /// + ExToggleExpandTabs, + /// + ExToggleShowTabs, + /// + ExToggleUndo, + /// + ExToggleReadOnly, + /// + ExToggleKeepBackups, + /// + ExToggleMatchCase, + /// + ExToggleBackSpKillTab, + /// + ExToggleDeleteKillTab, + /// + ExToggleSpaceTabs, + /// + ExToggleIndentWithTabs, + /// + ExToggleBackSpUnindents, + /// + ExToggleWordWrap, + /// + ExToggleTrim, + /// + ExToggleShowMarkers, + /// + ExSetLeftMargin, + /// + ExSetRightMargin, + /// + ExToggleSysClipboard, + /// + ExSetPrintDevice, + /// + ExChangeTabSize, + /// + ExChangeLeftMargin, + /// + ExChangeRightMargin, + /// + + + // Other commands + ExShowPosition, + /// Show internal position information on status line + ExShowVersion, + /// Show editor version information + ExShowKey, + /// Wait for keypress and display modifiers+key pressed + ExWinRefresh, + /// Refresh display + + ExMainMenu, + /// Activate main menu + ExShowMenu, + /// Popup menu specified as argument + ExLocalMenu, + /// Popup context menu + + ExChangeMode, + /// Change active mode for current buffer + ExChangeKeys, + /// Change keybindings for current buffer + ExChangeFlags, + /// Change option flags for current buffer + + ExCancel, + /// + ExActivate, + /// + ExRescan, + /// + ExCloseActivate, + /// + ExActivateInOtherWindow, + /// + ExDeleteFile, + /// + + ExASCIITable, + /// Display ASCII selector in status line. + ExDesktopSave, + /// Save desktop + ExClipClear, + /// Clear clipboard + ExDesktopSaveAs, + /// Save desktop under a new name + ExChildClose, + /// + + ExBufListFileSave, + /// Save currently selected file in buffer list + ExBufListFileClose, + /// Close currently selected file in buffer list + + ExViewModeMap, + /// View current mode keybindings + ExClearMessages, + /// Clear compiler messages + + + ExIndentFunction, + /// Indent current function + ExMoveFunctionPrev, + /// Move cursor to previous function + ExMoveFunctionNext, + /// Move cursor to next function + ExInsertDate, + /// Insert date at cursor + ExInsertUid, + /// Insert user name at cursor + + ExFrameNew, + /// + ExFrameClose, + /// + ExFrameNext, + /// + ExFramePrev, + /// + + ExBufferViewNext, + /// + ExBufferViewPrev, + /// + + ExShowHelpWord, + /// Show context help on keyword. + ExShowHelp, + /// Show help for FTE. + ExConfigRecompile, + /// Recompile editor configuration + + ExSetCIndentStyle, + /// Set C indentation style parameters + /// Has the following parameters: + /// + /// C_Indent = 4; + /// C_BraceOfs = 0; + /// C_ParenDelta = -1; + /// C_CaseOfs = 0; + /// C_CaseDelta = 4; + /// C_ClassOfs = 0; + /// C_ClassDelta = 4; + /// C_ColonOfs = -4; + /// C_CommentOfs = 0; + /// C_CommentDelta = 1; + /// C_FirstLevelWidth = -1; + /// C_FirstLevelIndent = 4; + /// C_Continuation = 4; + ExSetIndentWithTabs, + /// Set value of indent-with-tabs to argument + ExRunProgramAsync +} ExCommands; + +#endif diff --git a/src/c_config.cpp b/src/c_config.cpp new file mode 100644 index 0000000..7a4fe7b --- /dev/null +++ b/src/c_config.cpp @@ -0,0 +1,1124 @@ +/* c_config.cpp + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#include "fte.h" + +typedef struct _CurPos { + int sz; + const char *a; + const char *c; + const char *z; + int line; + const char *name; // filename +} CurPos; + +#ifdef CONFIG_INDENT_C +extern int C_Indent; +extern int C_BraceOfs; +extern int C_CaseOfs; +extern int C_CaseDelta; +extern int C_ClassOfs; +extern int C_ClassDelta; +extern int C_ColonOfs; +extern int C_CommentOfs; +extern int C_CommentDelta; +extern int C_FirstLevelWidth; +extern int C_FirstLevelIndent; +extern int C_Continuation; +extern int C_ParenDelta; +#endif + +#ifdef CONFIG_INDENT_REXX +extern int REXX_Base_Indent; +extern int REXX_Do_Offset; +#endif + +extern int ShowVScroll; +extern int ShowHScroll; +extern int ShowMenuBar; + +int SystemClipboard = 0; +int ScreenSizeX = -1, ScreenSizeY = -1; +int ScrollBarWidth = 1; +int CursorInsSize[2] = { 90, 100 }; +int CursorOverSize[2] = { 0, 100 }; +int OpenAfterClose = 1; +int SelectPathname = 0; +char DefaultModeName[32] = ""; +RxNode *CompletionFilter = NULL; +#if defined(DOS) || defined(DOSP32) +char PrintDevice[MAXPATH] = "PRN"; +#else +char PrintDevice[MAXPATH] = "\\DEV\\PRN"; +#endif +char CompileCommand[256] = "make"; +int KeepHistory = 0; +int LoadDesktopOnEntry = 0; +int SaveDesktopOnExit = 0; +char WindowFont[64] = ""; +int KeepMessages = 0; +int ScrollBorderX = 0; +int ScrollBorderY = 0; +int ScrollJumpX = 8; +int ScrollJumpY = 1; +int GUIDialogs = 1; +int PMDisableAccel = 0; +int SevenBit = 0; +int WeirdScroll = 0; +int LoadDesktopMode = 0; +char HelpCommand[128] = "man -a"; +char *ConfigSourcePath = 0; + +#ifdef CONFIG_SYNTAX_HILIT +int AddKeyword(ColorKeywords *tab, char color, const char *keyword) { + int len; + + len = strlen(keyword); + if (len < 1 || len >= CK_MAXLEN) return 0; + + if (tab->key[len]) { + int lx = strlen(tab->key[len]); + char *key; + + key = (char *)realloc(tab->key[len], lx + len + 1 + 1); + assert(key != NULL); + + tab->key[len] = key; + assert(tab->key[len] != 0); + strcpy(tab->key[len] + lx, keyword); + tab->key[len][lx + len] = color; + tab->key[len][lx + len + 1] = 0; + } else { + tab->key[len] = (char *)malloc(len + 2); + assert(tab->key[len] != 0); + strcpy(tab->key[len], keyword); + tab->key[len][len] = color; + tab->key[len][len + 1] = 0; + } + tab->count[len]++; + tab->TotalCount++; + return 1; +} +#endif + +int SetModeNumber(EMode *mode, int what, int number) { + int j = what; + + if (j == BFI_LeftMargin || j == BFI_RightMargin) number--; + mode->Flags.num[j] = number; + return 0; +} + +int SetModeString(EMode *mode, int what, const char *string) { + int j = what; + +#ifdef CONFIG_SYNTAX_HILIT + if (j == BFI_Colorizer) { + mode->fColorize = FindColorizer(string); + } else +#endif + if (j == BFI_EventMap) { + mode->fEventMap = FindEventMap(string); + } else if (j == BFI_IndentMode) { + mode->Flags.num[j] = GetIndentMode(string); + } else if (j == BFS_WordChars) { + SetWordChars(mode->Flags.WordChars, string); + } else if (j == BFS_CapitalChars) { + SetWordChars(mode->Flags.CapitalChars, string); + } else if (j == BFS_FileNameRx) { + if (mode->MatchName) + free(mode->MatchName); + if (mode->MatchNameRx) + RxFree(mode->MatchNameRx); + mode->MatchName = strdup(string); + mode->MatchNameRx = RxCompile(string); + } else if (j == BFS_FirstLineRx) { + if (mode->MatchLine) + free(mode->MatchLine); + if (mode->MatchLineRx) + RxFree(mode->MatchLineRx); + mode->MatchLine = strdup(string); + mode->MatchLineRx = RxCompile(string); + } else { + if (mode->Flags.str[j & 0xFF]) + free(mode->Flags.str[j & 0xFF]); + mode->Flags.str[j & 0xFF] = strdup(string); + } + return 0; +} + +int SetGlobalNumber(int what, int number) { + switch (what) { +#ifdef CONFIG_INDENT_C + case FLAG_C_Indent: C_Indent = number; break; + case FLAG_C_BraceOfs: C_BraceOfs = number; break; + case FLAG_C_CaseOfs: C_CaseOfs = number; break; + case FLAG_C_CaseDelta: C_CaseDelta = number; break; + case FLAG_C_ClassOfs: C_ClassOfs = number; break; + case FLAG_C_ClassDelta: C_ClassDelta = number; break; + case FLAG_C_ColonOfs: C_ColonOfs = number; break; + case FLAG_C_CommentOfs: C_CommentOfs = number; break; + case FLAG_C_CommentDelta: C_CommentDelta = number; break; + case FLAG_C_FirstLevelIndent: C_FirstLevelIndent = number; break; + case FLAG_C_FirstLevelWidth: C_FirstLevelWidth = number; break; + case FLAG_C_Continuation: C_Continuation = number; break; + case FLAG_C_ParenDelta: C_ParenDelta = number; break; +#endif +#ifdef CONFIG_INDENT_REXX + case FLAG_REXX_Indent: REXX_Base_Indent = number; break; + case FLAG_REXX_Do_Offset: REXX_Do_Offset = number; break; +#endif + case FLAG_ScreenSizeX: ScreenSizeX = number; break; + case FLAG_ScreenSizeY: ScreenSizeY = number; break; + case FLAG_CursorInsertStart: CursorInsSize[0] = number; break; + case FLAG_CursorInsertEnd: CursorInsSize[1] = number; break; + case FLAG_CursorOverStart: CursorOverSize[0] = number; break; + case FLAG_CursorOverEnd: CursorOverSize[1] = number; break; + case FLAG_SysClipboard: SystemClipboard = number; break; + case FLAG_OpenAfterClose: OpenAfterClose = number; break; + case FLAG_ShowVScroll: ShowVScroll = number; break; + case FLAG_ShowHScroll: ShowHScroll = number; break; + case FLAG_ScrollBarWidth: ScrollBarWidth = number; break; + case FLAG_SelectPathname: SelectPathname = number; break; + case FLAG_ShowMenuBar: ShowMenuBar = number; break; + case FLAG_ShowToolBar: ShowToolBar = number; break; + case FLAG_KeepHistory: KeepHistory = number; break; + case FLAG_LoadDesktopOnEntry: LoadDesktopOnEntry = number; break; + case FLAG_SaveDesktopOnExit: SaveDesktopOnExit = number; break; + case FLAG_KeepMessages: KeepMessages = number; break; + case FLAG_ScrollBorderX: ScrollBorderX = number; break; + case FLAG_ScrollBorderY: ScrollBorderY = number; break; + case FLAG_ScrollJumpX: ScrollJumpX = number; break; + case FLAG_ScrollJumpY: ScrollJumpY = number; break; + case FLAG_GUIDialogs: GUIDialogs = number; break; + case FLAG_PMDisableAccel: PMDisableAccel = number; break; + case FLAG_SevenBit: SevenBit = number; break; + case FLAG_WeirdScroll: WeirdScroll = number; break; + case FLAG_LoadDesktopMode: LoadDesktopMode = number; break; + default: + return -1; + } + return 0; +} + +int SetGlobalString(long what, const char *string) { + switch (what) { + case FLAG_DefaultModeName: strcpy(DefaultModeName, string); break; + case FLAG_CompletionFilter: if ((CompletionFilter = RxCompile(string)) == NULL) return -1; break; + case FLAG_PrintDevice: strcpy(PrintDevice, string); break; + case FLAG_CompileCommand: strcpy(CompileCommand, string); break; + case FLAG_WindowFont: strcpy(WindowFont, string); break; + case FLAG_HelpCommand: strcpy(HelpCommand, string); break; + default: + return -1; + } + return 0; +} + +int SetEventString(EEventMap *Map, long what, const char *string) { + switch (what) { + case EM_MainMenu: + case EM_LocalMenu: + Map->SetMenu(what, string); + break; + default: + return -1; + } + return 0; +} + +#ifdef CONFIG_SYNTAX_HILIT +int SetColorizeString(EColorize *Colorize, long what, const char *string) { + switch (what) { + case COL_SyntaxParser: + Colorize->SyntaxParser = GetHilitMode(string); + break; + default: + return -1; + } + return 0; +} +#endif + +unsigned char GetObj(CurPos &cp, unsigned short &len) { + len = 0; + if (cp.c + 3 <= cp.z) { + unsigned char c; + unsigned char l[2]; + c = *cp.c++; + memcpy(l, cp.c, 2); + len = (l[1] << 8) + l[0]; + cp.c += 2; + return c; + } + return 0xFF; +} + +const char *GetCharStr(CurPos &cp, unsigned short len) { + const char *p = cp.c; + if (cp.c + len > cp.z) + return 0; + cp.c += len; + return p; +} + +int GetNum(CurPos &cp, long &num) { + unsigned char n[4]; + if (cp.c + 4 > cp.z) return 0; + memcpy(n, cp.c, 4); + num = + (n[3] << 24) + + (n[2] << 16) + + (n[1] << 8) + + n[0]; + + if ((n[3] > 127) && sizeof(long) > 4) + num = num | (~0xFFFFFFFFUL); + cp.c += 4; + return 1; +} + +int ReadCommands(CurPos &cp, const char *Name) { + unsigned char obj; + unsigned short len; + long Cmd = NewCommand(Name); + long cmdno; + + if (GetObj(cp, len) != CF_INT) return-1; + if (GetNum(cp, cmdno) == 0) return -1; + if (cmdno != (Cmd | CMD_EXT)) { + fprintf(stderr, "Bad Command map %s -> %ld != %ld\n", Name, Cmd, cmdno); + return -1; + } + + while ((obj = GetObj(cp, len)) != 0xFF) { + switch (obj) { + case CF_COMMAND: + { + // char *s; + long cnt; + long ign; + long cmd; + + // if ((s = GetCharStr(cp, len)) == 0) return -1; + if (GetNum(cp, cmd) == 0) return -1; + if (GetObj(cp, len) != CF_INT) return -1; + if (GetNum(cp, cnt) == 0) return -1; + if (GetObj(cp, len) != CF_INT) return -1; + if (GetNum(cp, ign) == 0) return -1; + + // if (cmd != CmdNum(s)) { + // fprintf(stderr, "Bad Command Id: %s -> %d\n", s, cmd); + // return -1; + // } + + if (AddCommand(Cmd, cmd, cnt, ign) == 0) { + if (Name == 0 || strcmp(Name, "xx") != 0) { + fprintf(stderr, "Bad Command Id: %ld\n", cmd); + return -1; + } + } + } + break; + case CF_STRING: + { + const char *s = GetCharStr(cp, len); + + if (s == 0) return -1; + if (AddString(Cmd, s) == 0) return -1; + } + break; + case CF_INT: + { + long num; + + if (GetNum(cp, num) == 0) return -1; + if (AddNumber(Cmd, num) == 0) return -1; + } + break; + case CF_VARIABLE: + { + long num; + + if (GetNum(cp, num) == 0) return -1; + if (AddVariable(Cmd, num) == 0) return -1; + } + break; + case CF_CONCAT: + if (AddConcat(Cmd) == 0) return -1; + break; + case CF_END: + return Cmd; + default: + return -1; + } + } + return -1; +} + +int ReadMenu(CurPos &cp, const char *MenuName) { + unsigned char obj; + unsigned short len; + + int menu = -1, item = -1; + + menu = NewMenu(MenuName); + + while ((obj = GetObj(cp, len)) != 0xFF) { + switch (obj) { + case CF_ITEM: + { + if (len == 0) { + item = NewItem(menu, 0); + } else { + const char *s = GetCharStr(cp, len); + int Cmd; + if (s == 0) return -1; + item = NewItem(menu, s); + if ((obj = GetObj(cp, len)) != CF_MENUSUB) return -1; + if ((Cmd = ReadCommands(cp, 0)) == -1) return -1; + Menus[menu].Items[item].Cmd = Cmd + 65536; + } + } + break; + case CF_SUBMENU: + { + const char *s = GetCharStr(cp, len); + const char *w; + + if ((obj = GetObj(cp, len)) != CF_STRING) return -1; + if ((w = GetCharStr(cp, len)) == 0) return -1; + item = NewSubMenu(menu, s, GetMenuId(w), SUBMENU_NORMAL); + } + break; + + case CF_SUBMENUCOND: + { + const char *s = GetCharStr(cp, len); + const char *w; + + if ((obj = GetObj(cp, len)) != CF_STRING) return -1; + if ((w = GetCharStr(cp, len)) == 0) return -1; + item = NewSubMenu(menu, s, GetMenuId(w), SUBMENU_CONDITIONAL); + } + break; + + case CF_END: + return 0; + default: + return -1; + } + } + return -1; +} + +int ReadColors(CurPos &cp, const char *ObjName) { + unsigned char obj; + unsigned short len; + + while ((obj = GetObj(cp, len)) != 0xFF) { + switch (obj) { + case CF_STRING: + { + char cl[30]; + const char *sname = GetCharStr(cp, len); + const char *svalue; + if (sname == 0) return -1; + if ((obj = GetObj(cp, len)) != CF_STRING) return -1; + if ((svalue = GetCharStr(cp, len)) == 0) return -1; + strcpy(cl, ObjName); + strcat(cl, "."); + strcat(cl, sname); + if (SetColor(cl, svalue) == 0) return -1; + } + break; + case CF_END: + return 0; + default: + return -1; + } + } + return -1; +} + +#ifdef CONFIG_SYNTAX_HILIT +int ReadHilitColors(CurPos &cp, EColorize *Colorize, const char * /*ObjName*/) { + unsigned char obj; + unsigned short len; + + while ((obj = GetObj(cp, len)) != 0xFF) { + switch (obj) { + case CF_INT: + { + long cidx; + const char *svalue; + + if (GetNum(cp, cidx) == 0) return -1; + if ((obj = GetObj(cp, len)) != CF_STRING) + return -1; + if ((svalue = GetCharStr(cp, len)) == 0) + return -1; + if (Colorize->SetColor(cidx, svalue) == 0) + return -1; + } + break; + case CF_END: + return 0; + default: + return -1; + } + } + return -1; +} + +int ReadKeywords(CurPos &cp, ColorKeywords *keywords, int color) { + unsigned char obj; + unsigned short len; + + while ((obj = GetObj(cp, len)) != 0xFF) { + switch (obj) { + case CF_STRING: + { + const char *kname = GetCharStr(cp, len); + if (kname == 0) return -1; + if (AddKeyword(keywords, (char) color, kname) != 1) return -1; + } + break; + case CF_END: + return 0; + default: + return -1; + } + } + return -1; +} +#endif + +int ReadEventMap(CurPos &cp, EEventMap *Map, const char * /*MapName*/) { + unsigned char obj; + unsigned short len; + + while ((obj = GetObj(cp, len)) != 0xFF) { + switch (obj) { + case CF_KEY: + { + EKey *Key; + const char *s; + int Cmd; + + if ((s = GetCharStr(cp, len)) == 0) return -1; + if ((Key = SetKey(Map, s)) == 0) return -1; + if ((obj = GetObj(cp, len)) != CF_KEYSUB) return -1; + if ((Cmd = ReadCommands(cp, 0)) == -1) return -1; + Key->Cmd = Cmd; + } + break; + +#ifdef CONFIG_ABBREV + case CF_ABBREV: + { + EAbbrev *Ab; + const char *s; + const char *x; + int Cmd; + + if ((s = GetCharStr(cp, len)) == 0) return -1; + obj = GetObj(cp, len); + if (obj == CF_KEYSUB) { + if ((Cmd = ReadCommands(cp, 0)) == -1) return -1; + Ab = new EAbbrev(s, Cmd); + } else if (obj == CF_STRING) { + x = GetCharStr(cp, len); + Ab = new EAbbrev(s, x); + } else + return -1; + if (Ab) { + Map->AddAbbrev(Ab); + } + } + break; +#endif + + case CF_SETVAR: + { + long what; + + if (GetNum(cp, what) == 0) return -1; + switch (GetObj(cp, len)) { + case CF_STRING: + { + const char *val = GetCharStr(cp, len); + if (len == 0) return -1; + if (SetEventString(Map, what, val) != 0) return -1; + } + break; + /* case CF_INT: + { + long num; + + if (GetNum(cp, num) == 0) return -1; + if (SetModeNumber(Mode, what, num) != 0) return -1; + } + break;*/ + default: + return -1; + } + } + break; + case CF_END: + return 0; + default: + return -1; + } + } + return -1; +} + +#ifdef CONFIG_SYNTAX_HILIT +int ReadColorize(CurPos &cp, EColorize *Colorize, const char *ModeName) { + unsigned char obj; + unsigned short len; + + long LastState = -1; + + while ((obj = GetObj(cp, len)) != 0xFF) { + switch (obj) { + case CF_COLOR: + if (ReadHilitColors(cp, Colorize, ModeName) == -1) return -1; + break; + + case CF_KEYWORD: + { + const char *colorstr; + + if ((colorstr = GetCharStr(cp, len)) == 0) return -1; + + unsigned int Col; + unsigned int ColBg, ColFg; + + if (sscanf(colorstr, "%1X %1X", &ColFg, &ColBg) != 2) + return 0; + + Col = ColFg | (ColBg << 4); + + int color = ChColor(Col); + if (ReadKeywords(cp, &Colorize->Keywords, color) == -1) return -1; + } + break; + + case CF_HSTATE: + { + long stateno; + long color; + + if (Colorize->hm == 0) + Colorize->hm = new HMachine(); + + assert(Colorize->hm != 0); + + if (GetNum(cp, stateno) == 0) + return -1; + + assert(stateno == LastState + 1); + + obj = GetObj(cp, len); + assert(obj == CF_INT); + + if (GetNum(cp, color) == 0) + return -1; + + HState newState; + + newState.InitState(); + + newState.color = color; + + Colorize->hm->AddState(newState); + LastState = stateno; + } + break; + + case CF_HTRANS: + { + HTrans newTrans; + long nextState; + long matchFlags; + const char *match; + long color; + + if (GetNum(cp, nextState) == 0) + return -1; + obj = GetObj(cp, len); + assert(obj == CF_INT); + if (GetNum(cp, matchFlags) == 0) + return -1; + obj = GetObj(cp, len); + assert(obj == CF_INT); + if (GetNum(cp, color) == 0) + return -1; + obj = GetObj(cp, len); + assert(obj == CF_STRING); + if ((match = GetCharStr(cp, len)) == 0) + return -1; + + newTrans.InitTrans(); + + newTrans.matchFlags = matchFlags; + newTrans.nextState = nextState; + newTrans.color = color; + + if ((newTrans.matchFlags & MATCH_SET) || + (newTrans.matchFlags & MATCH_NOTSET)) + { + newTrans.matchLen = 1; + newTrans.match = (char *)malloc(256/8); + assert(newTrans.match != NULL); + SetWordChars(newTrans.match, match); + } else { + newTrans.match = strdup(match); + newTrans.matchLen = strlen(match); + } + + Colorize->hm->AddTrans(newTrans); + } + break; + + case CF_HWTYPE: + { + long nextKwdMatchedState; + long nextKwdNotMatchedState; + long nextKwdNoCharState; + long options; + const char *wordChars; + + obj = GetObj(cp, len); + assert(obj == CF_INT); + if (GetNum(cp, nextKwdMatchedState) == 0) + return -1; + + obj = GetObj(cp, len); + assert(obj == CF_INT); + if (GetNum(cp, nextKwdNotMatchedState) == 0) + return -1; + + obj = GetObj(cp, len); + assert(obj == CF_INT); + if (GetNum(cp, nextKwdNoCharState) == 0) + return -1; + + obj = GetObj(cp, len); + assert(obj == CF_INT); + if (GetNum(cp, options) == 0) + return -1; + + obj = GetObj(cp, len); + assert(obj == CF_STRING); + if ((wordChars = GetCharStr(cp, len)) == 0) + return -1; + + Colorize->hm->LastState()->options = options; + Colorize->hm->LastState()->nextKwdMatchedState = nextKwdMatchedState; + Colorize->hm->LastState()->nextKwdNotMatchedState = nextKwdNotMatchedState; + Colorize->hm->LastState()->nextKwdNoCharState = nextKwdNoCharState; + + if (wordChars && *wordChars) { + Colorize->hm->LastState()->wordChars = (char *)malloc(256/8); + assert(Colorize->hm->LastState()->wordChars != NULL); + SetWordChars(Colorize->hm->LastState()->wordChars, wordChars); + } + } + break; + + case CF_HWORDS: + { + const char *colorstr; + int color; + + if ((colorstr = GetCharStr(cp, len)) == 0) return -1; + + color = hcPlain_Keyword; + + if (strcmp(colorstr, "-") != 0) { + const char *Value = colorstr; + int Col; + + if (*Value == '-') { + Value++; + if (sscanf(Value, "%1X", &Col) != 1) return -1; + Col |= (hcPlain_Background & 0xF0); + } else if (Value[1] == '-') { + if (sscanf(Value, "%1X", &Col) != 1) return -1; + Col <<= 4; + Col |= (hcPlain_Background & 0x0F); + } else { + if (sscanf(Value, "%2X", &Col) != 1) return -1; + } + color = Col; + } + if (ReadKeywords(cp, &Colorize->hm->LastState()->keywords, color) == -1) return -1; + } + break; + + case CF_SETVAR: + { + long what; + + if (GetNum(cp, what) == 0) return -1; + switch (GetObj(cp, len)) { + case CF_STRING: + { + const char *val = GetCharStr(cp, len); + if (len == 0) return -1; + if (SetColorizeString(Colorize, what, val) != 0) return -1; + } + break; + /* case CF_INT: + { + long num; + + if (GetNum(cp, num) == 0) return -1; + if (SetModeNumber(Mode, what, num) != 0) return -1; + } + break;*/ + default: + return -1; + } + } + break; + case CF_END: + return 0; + default: + return -1; + } + } + return -1; +} +#endif + +int ReadMode(CurPos &cp, EMode *Mode, const char * /*ModeName*/) { + unsigned char obj; + unsigned short len; + + while ((obj = GetObj(cp, len)) != 0xFF) { + switch (obj) { + case CF_SETVAR: + { + long what; + + if (GetNum(cp, what) == 0) return -1; + switch (GetObj(cp, len)) { + case CF_STRING: + { + const char *val = GetCharStr(cp, len); + if (len == 0) return -1; + if (SetModeString(Mode, what, val) != 0) return -1; + } + break; + case CF_INT: + { + long num; + + if (GetNum(cp, num) == 0) return -1; + if (SetModeNumber(Mode, what, num) != 0) return -1; + } + break; + default: + return -1; + } + } + break; + case CF_END: + return 0; + default: + return -1; + } + } + return -1; +} + +int ReadObject(CurPos &cp, const char *ObjName) { + unsigned char obj; + unsigned short len; + + while ((obj = GetObj(cp, len)) != 0xFF) { + switch (obj) { + case CF_COLOR: + if (ReadColors(cp, ObjName) == -1) return -1; + break; +#ifdef CONFIG_OBJ_MESSAGES + case CF_COMPRX: + { + long file, line, msg; + const char *regexp; + + if (GetObj(cp, len) != CF_INT) return -1; + if (GetNum(cp, file) == 0) return -1; + if (GetObj(cp, len) != CF_INT) return -1; + if (GetNum(cp, line) == 0) return -1; + if (GetObj(cp, len) != CF_INT) return -1; + if (GetNum(cp, msg) == 0) return -1; + if (GetObj(cp, len) != CF_REGEXP) return -1; + if ((regexp = GetCharStr(cp, len)) == 0) return -1; + + if (AddCRegexp(file, line, msg, regexp) == 0) return -1; + } + break; +#endif + case CF_SETVAR: + { + long what; + if (GetNum(cp, what) == 0) return -1; + + switch (GetObj(cp, len)) { + case CF_STRING: + { + const char *val = GetCharStr(cp, len); + if (len == 0) return -1; + if (SetGlobalString(what, val) != 0) return -1; + } + break; + case CF_INT: + { + long num; + + if (GetNum(cp, num) == 0) return -1; + if (SetGlobalNumber(what, num) != 0) return -1; + } + break; + default: + return -1; + } + } + break; + case CF_END: + return 0; + default: + return -1; + } + } + return -1; +} + +int ReadConfigFile(CurPos &cp) { + unsigned char obj; + unsigned short len; + + { + const char *p; + + obj = GetObj(cp, len); + assert(obj == CF_STRING); + if ((p = GetCharStr(cp, len)) == 0) + return -1; + + if (ConfigSourcePath) + free(ConfigSourcePath); + + ConfigSourcePath = strdup(p); + } + + while ((obj = GetObj(cp, len)) != 0xFF) { + switch (obj) { + case CF_SUB: + { + const char *CmdName = GetCharStr(cp, len); + + if (ReadCommands(cp, CmdName) == -1) return -1; + } + break; + case CF_MENU: + { + const char *MenuName = GetCharStr(cp, len); + + if (ReadMenu(cp, MenuName) == -1) return -1; + } + break; + case CF_EVENTMAP: + { + EEventMap *EventMap = 0; + const char *MapName = GetCharStr(cp, len); + const char *UpMap = 0; + + if ((obj = GetObj(cp, len)) != CF_PARENT) return -1; + if (len > 0) + if ((UpMap = GetCharStr(cp, len)) == 0) return -1; + + // add new mode + if ((EventMap = FindEventMap(MapName)) == 0) { + EEventMap *OrgMap = 0; + + if (strcmp(UpMap, "") != 0) + OrgMap = FindEventMap(UpMap); + EventMap = new EEventMap(MapName, OrgMap); + } else { + if (EventMap->Parent == 0) + EventMap->Parent = FindEventMap(UpMap); + } + if (ReadEventMap(cp, EventMap, MapName) == -1) return -1; + } + break; + + case CF_COLORIZE: + { + EColorize *Mode = 0; + const char *ModeName = GetCharStr(cp, len); + const char *UpMode = 0; + + if ((obj = GetObj(cp, len)) != CF_PARENT) return -1; + if (len > 0) + if ((UpMode = GetCharStr(cp, len)) == 0) return -1; + + // add new mode + if ((Mode = FindColorizer(ModeName)) == 0) + Mode = new EColorize(ModeName, UpMode); + else { + if (Mode->Parent == 0) + Mode->Parent = FindColorizer(UpMode); + } + if (ReadColorize(cp, Mode, ModeName) == -1) + return -1; + } + break; + + case CF_MODE: + { + EMode *Mode = 0; + const char *ModeName = GetCharStr(cp, len); + const char *UpMode = 0; + + if ((obj = GetObj(cp, len)) != CF_PARENT) return -1; + if (len > 0) + if ((UpMode = GetCharStr(cp, len)) == 0) return -1; + + // add new mode + if ((Mode = FindMode(ModeName)) == 0) { + EMode *OrgMode = 0; + EEventMap *Map; + + if (strcmp(UpMode, "") != 0) + OrgMode = FindMode(UpMode); + Map = FindEventMap(ModeName); + if (Map == 0) { + EEventMap *OrgMap = 0; + + if (strcmp(UpMode, "") != 0) + OrgMap = FindEventMap(UpMode); + Map = new EEventMap(ModeName, OrgMap); + } + Mode = new EMode(OrgMode, Map, ModeName); + Mode->fNext = Modes; + Modes = Mode; + } else { + if (Mode->fParent == 0) + Mode->fParent = FindMode(UpMode); + } + if (ReadMode(cp, Mode, ModeName) == -1) + return -1; + } + break; + case CF_OBJECT: + { + const char *ObjName; + + if ((ObjName = GetCharStr(cp, len)) == 0) + return -1; + if (ReadObject(cp, ObjName) == -1) + return -1; + } + break; + case CF_EOF: + return 0; + default: + return -1; + } + } + return -1; +} + +int LoadConfig(int /*argc*/, char ** /*argv*/, char *CfgFileName) { + int fd, rc; + char *buffer = 0; + struct stat statbuf; + CurPos cp; + + if ((fd = open(CfgFileName, O_RDONLY | O_BINARY)) == -1) + return -1; + if (fstat(fd, &statbuf) != 0) { + close(fd); + return -1; + } + buffer = (char *) malloc(statbuf.st_size); + if (buffer == 0) { + close(fd); + return -1; + } + if (read(fd, buffer, statbuf.st_size) != statbuf.st_size) { + close(fd); + free(buffer); + return -1; + } + close(fd); + + unsigned char l[4]; + unsigned long ln; + + memcpy(l, buffer, 4); + ln = (l[3] << 24) + (l[2] << 16) + (l[1] << 8) + l[0]; + + if (ln != CONFIG_ID) { + free(buffer); + DieError(0, "Bad .CNF signature"); + return -1; + } + + memcpy(l, buffer + 4, 4); + ln = (l[3] << 24) + (l[2] << 16) + (l[1] << 8) + l[0]; + + if (ln != VERNUM) { + free(buffer); + DieError(0, "Bad .CNF version."); + return -1; + } + + cp.name = CfgFileName; + cp.sz = statbuf.st_size; + cp.a = buffer; + cp.c = cp.a + 2 * 4; + cp.z = cp.a + cp.sz; + cp.line = 1; + + rc = ReadConfigFile(cp); + + free(buffer); + + if (rc == -1) { + DieError(1, "Error %s offset %d\n", CfgFileName, cp.c - cp.a); + } + return rc; +} + +#include "defcfg.h" + +int UseDefaultConfig() { + CurPos cp; + int rc; + + cp.name = "Internal Configuration"; + cp.sz = sizeof(DefaultConfig); + cp.a = (char *)DefaultConfig; + cp.c = (char *)DefaultConfig + 2 * 4; + cp.z = cp.a + cp.sz; + cp.line = 1; + + rc = ReadConfigFile(cp); + + if (rc == -1) + DieError(1, "Error %s offset %d\n", cp.name, cp.c - cp.a); + return rc; +} diff --git a/src/c_config.h b/src/c_config.h new file mode 100644 index 0000000..ad9561a --- /dev/null +++ b/src/c_config.h @@ -0,0 +1,49 @@ +/* c_config.h + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#ifndef __CONFIG_H +#define __CONFIG_H + +extern int ScreenSizeX; +extern int ScreenSizeY; +extern int CursorInsSize[2]; +extern int CursorOverSize[2]; +extern int SystemClipboard; +extern int OpenAfterClose; +extern int ShowMenuBar; +extern int ShowToolBar; +extern int SelectPathname; +extern char DefaultModeName[32]; +extern int WSStyleSearch; +extern char PrintDevice[MAXPATH]; +extern char CompileCommand[256]; +extern int KeepHistory; +extern int LoadDesktopOnEntry; +extern int SaveDesktopOnExit; +extern int KeepMessages; +extern int ScrollBorderX; +extern int ScrollBorderY; +extern int ScrollJumpX; +extern int ScrollJumpY; +extern int GUIDialogs; +extern int SevenBit; +extern int WeirdScroll; +extern int LoadDesktopMode; +extern char HelpCommand[128]; +extern char *ConfigSourcePath; +extern char ConfigFileName[MAXPATH]; + +int LoadConfig(int argc, char **argv, char *CfgFileName); +int GetIndentMode(const char *Str); +int GetHilitMode(const char *Str); +int UseDefaultConfig(); +int AddCRegexp(int file, int line, int msg, const char *regexp); +int LoadFile(char *WhereName, char *CfgName); + +#endif diff --git a/src/c_desktop.cpp b/src/c_desktop.cpp new file mode 100644 index 0000000..bf6c5bb --- /dev/null +++ b/src/c_desktop.cpp @@ -0,0 +1,162 @@ +/* c_desktop.cpp + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#include "fte.h" + +#ifdef CONFIG_DESKTOP + +#define DESKTOP_VER "FTE Desktop 2\n" +#define DESKTOP_VER1 "FTE Desktop 1\n" + +char DesktopFileName[256] = ""; + +int SaveDesktop(char *FileName) { + FILE *fp; + EModel *M; + + fp = fopen(FileName, "w"); + if (fp == 0) + return 0; + + setvbuf(fp, FileBuffer, _IOFBF, sizeof(FileBuffer)); + + fprintf(fp, DESKTOP_VER); + + M = ActiveModel; + while (M) { + switch(M->GetContext()) { + case CONTEXT_FILE: + { + EBuffer *B = (EBuffer *)M; + fprintf(fp, "F|%d|%s\n", B->ModelNo, B->FileName); + } + break; +#ifdef CONFIG_OBJ_DIRECTORY + case CONTEXT_DIRECTORY: + { + EDirectory *D = (EDirectory *)M; + fprintf(fp, "D|%d|%s\n", D->ModelNo, D->Path); + } + break; +#endif + } + M = M->Next; + if (M == ActiveModel) + break; + } +#ifdef CONFIG_TAGS + TagsSave(fp); +#endif + markIndex.saveToDesktop(fp); + fclose(fp); + return 1; +} + +int LoadDesktop(char *FileName) { + FILE *fp; + char line[512]; + char *p, *e; + int FLCount = 0; + +#ifdef CONFIG_TAGS + TagClear(); +#endif + + fp = fopen(FileName, "r"); + if (fp == 0) + return 0; + + //setvbuf(fp, FileBuffer, _IOFBF, sizeof(FileBuffer)); + + if (fgets(line, sizeof(line), fp) == 0 || + (strcmp(line, DESKTOP_VER) != 0 && + (strcmp(line, DESKTOP_VER1) != 0))) + { + fclose(fp); + return 0; + } + while (fgets(line, sizeof(line), fp) != 0) { + e = strchr(line, '\n'); + if (e == 0) + break; + *e = 0; + if ((line[0] == 'D' || line[0] == 'F') && line[1] == '|') { + int ModelNo = -1; + p = line + 2; + if (isdigit(*p)) { + ModelNo = atoi(p); + while (isdigit(*p)) p++; + if (*p == '|') + p++; + } + + if (line[0] == 'F') { // file + if (FLCount > 0) + suspendLoads = 1; + if (FileLoad(0, p, 0, ActiveView)) + FLCount++; + suspendLoads = 0; +#ifdef CONFIG_OBJ_DIRECTORY + } else if (line[0] == 'D') { // directory + EModel *m = new EDirectory(0, &ActiveModel, p); + assert(ActiveModel != 0 && m != 0); +#endif + } + + if (ActiveModel) { + if (ModelNo != -1) { + if (FindModelID(ActiveModel, ModelNo) == 0) + ActiveModel->ModelNo = ModelNo; + } + + if (ActiveModel != ActiveModel->Next) { + suspendLoads = 1; + ActiveView->SelectModel(ActiveModel->Next); + suspendLoads = 0; + } + } + } else { +#ifdef CONFIG_TAGS + if (line[0] == 'T' && line[1] == '|') { // tag file + TagsAdd(line + 2); +#endif + } else if (line[0] == 'M' && line[1] == '|') { // mark + char *name; + char *file; + EPoint P; + //long l; + char *e; + + p = line + 2; + P.Row = strtol(p, &e, 10); + if (*e != '|') + break; + p = e + 1; + P.Col = strtol(p, &e, 10); + if (*e != '|') + break; + p = e + 1; + name = p; + while (*p && *p != '|') + p++; + if (*p == '|') + *p++ = 0; + else + break; + file = p; + + markIndex.insert(name, file, P); + } + } + } + fclose(fp); + return 1; +} + +#endif diff --git a/src/c_desktop.h b/src/c_desktop.h new file mode 100644 index 0000000..59aed57 --- /dev/null +++ b/src/c_desktop.h @@ -0,0 +1,28 @@ +/* c_desktop.h + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#ifndef __DESKTOP_H__ +#define __DESKTOP_H__ + +#ifdef CONFIG_DESKTOP + +#ifdef UNIX +# define DESKTOP_NAME ".fte-desktop" +#else +# define DESKTOP_NAME "fte.dsk" +#endif + +extern char DesktopFileName[256]; + +int SaveDesktop(char *FileName); +int LoadDesktop(char *FileName); + +#endif + +#endif diff --git a/src/c_fconfig.h b/src/c_fconfig.h new file mode 100644 index 0000000..32c7bd0 --- /dev/null +++ b/src/c_fconfig.h @@ -0,0 +1,48 @@ +/* c_fconfig.h + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#ifndef __FCONFIG_H__ +#define __FCONFIG_H__ + +#define CF_STRING 1 +#define CF_INT 2 +#define CF_REGEXP 3 + +#define CF_END 100 +#define CF_SUB 101 +#define CF_MENU 102 +#define CF_OBJECT 103 +#define CF_COMMAND 104 +#define CF_ITEM 105 +#define CF_SUBMENU 106 +#define CF_MENUSUB 107 +#define CF_MODE 108 +#define CF_PARENT 109 +#define CF_KEYSUB 110 +#define CF_KEY 111 +#define CF_COLOR 112 +#define CF_KEYWORD 113 +#define CF_SETVAR 114 +#define CF_COMPRX 115 +#define CF_EVENTMAP 116 +#define CF_COLORIZE 117 +#define CF_ABBREV 118 +#define CF_HSTATE 119 +#define CF_HTRANS 120 +#define CF_HWORDS 121 +#define CF_SUBMENUCOND 122 +#define CF_HWTYPE 123 +#define CF_VARIABLE 124 +#define CF_CONCAT 125 + +#define CF_EOF 254 + +#define CONFIG_ID 0x1A1D70E1 + +#endif diff --git a/src/c_hilit.cpp b/src/c_hilit.cpp new file mode 100644 index 0000000..7054854 --- /dev/null +++ b/src/c_hilit.cpp @@ -0,0 +1,329 @@ +/* c_hilit.cpp + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#include "fte.h" + +#ifdef CONFIG_SYNTAX_HILIT +static const struct { + const char *Name; + int Num; + SyntaxProc Proc; +} HilitModes[] = { +{ "PLAIN", HILIT_PLAIN, Hilit_Plain }, +#ifdef CONFIG_HILIT_C +{ "C", HILIT_C, Hilit_C }, +#endif +#ifdef CONFIG_HILIT_REXX +{ "REXX", HILIT_REXX, Hilit_REXX }, +#endif +#ifdef CONFIG_HILIT_HTML +{ "HTML", HILIT_HTML, Hilit_HTML }, +#endif +#ifdef CONFIG_HILIT_PERL +{ "PERL", HILIT_PERL, Hilit_PERL }, +#endif +#ifdef CONFIG_HILIT_MAKE +{ "MAKE", HILIT_MAKE, Hilit_MAKE }, +#endif +#ifdef CONFIG_HILIT_DIFF +{ "DIFF", HILIT_DIFF, Hilit_DIFF }, +#endif +#ifdef CONFIG_HILIT_MERGE +{ "MERGE", HILIT_MERGE, Hilit_MERGE }, +#endif +#ifdef CONFIG_HILIT_IPF +{ "IPF", HILIT_IPF, Hilit_IPF }, +#endif +#ifdef CONFIG_HILIT_ADA +{ "Ada", HILIT_ADA, Hilit_ADA }, +#endif +#ifdef CONFIG_HILIT_MSG +{ "MSG", HILIT_MSG, Hilit_MSG }, +#endif +#ifdef CONFIG_HILIT_SH +{ "SH", HILIT_SH, Hilit_SH }, +#endif +#ifdef CONFIG_HILIT_PASCAL +{ "PASCAL", HILIT_PASCAL, Hilit_PASCAL }, +#endif +#ifdef CONFIG_HILIT_TEX +{ "TEX", HILIT_TEX, Hilit_TEX }, +#endif +#ifdef CONFIG_HILIT_FTE +{ "FTE", HILIT_FTE, Hilit_FTE }, +#endif +#ifdef CONFIG_HILIT_CATBS +{ "CATBS", HILIT_CATBS, Hilit_CATBS }, +#endif +#ifdef CONFIG_HILIT_SIMPLE +{ "SIMPLE", HILIT_SIMPLE, Hilit_SIMPLE }, +#endif +}; + +static const struct { + const char *Name; + int Num; +} IndentModes[] = { +#ifdef CONFIG_INDENT_C +{ "C", INDENT_C }, +#endif +#ifdef CONFIG_INDENT_REXX +{ "REXX", INDENT_REXX }, +#endif +#ifdef CONFIG_INDENT_SIMPLE +{ "SIMPLE", INDENT_REXX }, +#endif +{ "PLAIN", INDENT_PLAIN }, +}; + +EColorize *Colorizers = 0; + +int GetIndentMode(const char *Str) { + for (unsigned int i = 0; i < sizeof(IndentModes) / sizeof(IndentModes[0]); i++) + if (strcmp(Str, IndentModes[i].Name) == 0) + return IndentModes[i].Num; + return 0; +} + +int GetHilitMode(const char *Str) { + for (unsigned int i = 0; i < sizeof(HilitModes) / sizeof(HilitModes[0]); i++) + if (strcmp(Str, HilitModes[i].Name) == 0) + return HilitModes[i].Num; + return HILIT_PLAIN; +} + +SyntaxProc GetHilitProc(int id) { + for (unsigned int i = 0; i < sizeof(HilitModes) / sizeof(HilitModes[0]); i++) + if (id == HilitModes[i].Num) + return HilitModes[i].Proc; + return 0; +} + +#ifdef CONFIG_WORD_HILIT +int EBuffer::HilitAddWord(const char *Word) { + if (HilitFindWord(Word) == 1) + return 1; + WordList = (char **)realloc((void *)WordList, (1 + WordCount) * sizeof(char *)); + if (WordList == 0) return 0; + WordList[WordCount++] = strdup(Word); + FullRedraw(); + return 1; +} + +int EBuffer::HilitFindWord(const char *Word) { + for (int i = 0; i < WordCount; i++) { + if (BFI(this, BFI_MatchCase) == 1) { + if (strcmp(Word, WordList[i]) == 0) return 1; + } else { + if (stricmp(Word, WordList[i]) == 0) return 1; + } + } + return 0; +} + +int EBuffer::HilitRemoveWord(const char *Word) { + for (int i = 0; i < WordCount; i++) { + if (BFI(this, BFI_MatchCase) == 1) { + if (strcmp(Word, WordList[i]) != 0) continue; + } else { + if (stricmp(Word, WordList[i]) != 0) continue; + } + free(WordList[i]); + memmove(WordList + i, WordList + i + 1, sizeof(char *) * (WordCount - i - 1)); + WordCount--; + WordList = (char **)realloc((void *)WordList, WordCount * sizeof(char *)); + FullRedraw(); + return 1; + } + return 0; +} + +int EBuffer::HilitWord() { + PELine L = VLine(CP.Row); + char s[CK_MAXLEN + 2]; + int P, len = 0; + + P = CharOffset(L, CP.Col); + while ((P > 0) && ((ChClass(L->Chars[P - 1]) == 1) || (L->Chars[P - 1] == '_'))) + P--; + while (len < CK_MAXLEN && P < L->Count && (ChClass(L->Chars[P]) == 1 || L->Chars[P] == '_')) + s[len++] = L->Chars[P++]; + if (len == 0) + return 0; + s[len] = 0; + + return (HilitFindWord(s)) ? HilitRemoveWord(s) : HilitAddWord(s); +} +#endif + +/* ======================================================================= */ + +EColorize::EColorize(const char *AName, const char *AParent) { + Name = strdup(AName); + SyntaxParser = HILIT_PLAIN; + Next = Colorizers; + hm = 0; + Colorizers = this; + Parent = FindColorizer(AParent); + memset((void *)&Keywords, 0, sizeof(Keywords)); + memset((void *)Colors, 0, sizeof(Colors)); + if (Parent) { + SyntaxParser = Parent->SyntaxParser; + memcpy((void *)Colors, (void *)Parent->Colors, sizeof(Colors)); + } else { + SyntaxParser = HILIT_PLAIN; + } +} + +EColorize::~EColorize() { + free(Name); + + for (int i=0; iName) == 0) + return p; + p = p->Next; + } + return 0; +} + +int EColorize::SetColor(int idx, const char *Value) { + unsigned int Col; + unsigned int ColBg, ColFg; + ChColor C; + + if (sscanf(Value, "%1X %1X", &ColFg, &ColBg) != 2) + return 0; + + Col = ColFg | (ColBg << 4); + C = ChColor(Col); + + if (idx < 0 || idx >= COUNT_CLR) + return 0; + Colors[idx] = C; + return 1; +} + +/* ======================================================================= */ + +void HTrans::InitTrans() { + match = 0; + matchLen = 0; + matchFlags = 0; + nextState = 0; + color = 0; +} + +/* ======================================================================= */ + +void HState::InitState() { + memset((void *)&keywords, 0, sizeof(keywords)); + firstTrans = 0; + transCount = 0; + color = 0; + wordChars = 0; + options = 0; + nextKwdMatchedState = -1; + nextKwdNotMatchedState = -1; + nextKwdNoCharState = -1; +} + +int HState::GetHilitWord(int len, char *str, ChColor &clr) { + char *p; + + if (len >= CK_MAXLEN || len < 1) + return 0; + + p = keywords.key[len]; + if (options & STATE_NOCASE) { + while (p && *p) { + if (strnicmp(p, str, len) == 0) { + clr = p[len]; + return 1; + } + p += len + 1; + } + } else { + while (p && *p) { + if (memcmp(p, str, len) == 0) { + clr = p[len]; + return 1; + } + p += len + 1; + } + } + return 0; +} + +/* ======================================================================= */ + +HMachine::HMachine() { + stateCount = 0; + state = 0; + transCount = 0; + trans = 0; +} + +HMachine::~HMachine() { + + // free states + if (state) + { + int i; + + while(stateCount--) + { + for (i=0; i 0); + trans = (HTrans *)realloc(trans, (transCount + 1) * sizeof(HTrans) ); + assert( trans ); + state[stateCount - 1].transCount++; + trans[transCount] = aTrans; + transCount++; +} + +#endif diff --git a/src/c_hilit.h b/src/c_hilit.h new file mode 100644 index 0000000..5d6319b --- /dev/null +++ b/src/c_hilit.h @@ -0,0 +1,223 @@ +/* c_hilit.h + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#ifndef __HILIT_H__ +#define __HILIT_H__ + +typedef unsigned short hlState; +typedef unsigned char hsState; + +class EBuffer; +class ELine; + +#define HILIT_P(proc) \ + int proc(EBuffer *BF, int LN, PCell B, int Pos, int Width, ELine *Line, hlState &State, hsState *StateMap, int *ECol) + +//typedef int (*SyntaxProc)(EBuffer *BF, int LN, PCell B, int Pos, int Width, ELine *Line, hlState &State, hsState *StateMap); +typedef HILIT_P((*SyntaxProc)); + + +int Indent_Plain(EBuffer *B, int Line, int PosCursor); +HILIT_P(Hilit_Plain); + +#ifdef CONFIG_SYNTAX_HILIT +/* highlighting state */ + +#ifdef CONFIG_HILIT_C +HILIT_P(Hilit_C); +#endif +#ifdef CONFIG_HILIT_HTML +HILIT_P(Hilit_HTML); +#endif +#ifdef CONFIG_HILIT_PERL +HILIT_P(Hilit_PERL); +#endif +#ifdef CONFIG_HILIT_MAKE +HILIT_P(Hilit_MAKE); +#endif +#ifdef CONFIG_HILIT_REXX +HILIT_P(Hilit_REXX); +#endif +#ifdef CONFIG_HILIT_DIFF +HILIT_P(Hilit_DIFF); +#endif +#ifdef CONFIG_HILIT_MERGE +HILIT_P(Hilit_MERGE); +#endif +#ifdef CONFIG_HILIT_IPF +HILIT_P(Hilit_IPF); +#endif +#ifdef CONFIG_HILIT_ADA +HILIT_P(Hilit_ADA); +#endif +#ifdef CONFIG_HILIT_MSG +HILIT_P(Hilit_MSG); +#endif +#ifdef CONFIG_HILIT_SH +HILIT_P(Hilit_SH); +#endif +#ifdef CONFIG_HILIT_PASCAL +HILIT_P(Hilit_PASCAL); +#endif +#ifdef CONFIG_HILIT_TEX +HILIT_P(Hilit_TEX); +#endif +#ifdef CONFIG_HILIT_FTE +HILIT_P(Hilit_FTE); +#endif +#ifdef CONFIG_HILIT_CATBS +HILIT_P(Hilit_CATBS); +#endif +#ifdef CONFIG_HILIT_SIMPLE +HILIT_P(Hilit_SIMPLE); +#endif + +#ifdef CONFIG_INDENT_C +int Indent_C(EBuffer *B, int Line, int PosCursor); +#endif +#ifdef CONFIG_INDENT_REXX +int Indent_REXX(EBuffer *B, int Line, int PosCursor); +#endif +#ifdef CONFIG_INDENT_SIMPLE +int Indent_SIMPLE(EBuffer *B, int Line, int PosCursor); +#endif + + /* + * NT has 2-byte charcode and attribute... Following is not portable to non- + * intel; should be replaced by formal TCell definition' usage instead of + * assumed array.. (Jal) + */ +#ifdef NTCONSOLE +# define PCLI unsigned short +#else +# define PCLI unsigned char +#endif + +#define ColorChar() \ + do {\ + BPos = C - Pos; \ + if (B) \ + if (BPos >= 0 && BPos < Width) { \ + BPtr = (PCLI *) (B + BPos); \ + BPtr[0] = *p; \ + BPtr[1] = Color; \ + } \ + if (StateMap) StateMap[i] = (hsState)(State & 0xFF); \ + } while (0) + +// MoveChar(B, C - Pos, Width, *p, Color, 1); +// if (StateMap) StateMap[i] = State; } + +#define NextChar() do { i++; p++; len--; C++; } while (0) +#define ColorNext() do { ColorChar(); NextChar(); } while (0) + +#define HILIT_VARS(ColorNormal, Line) \ + PCLI *BPtr; \ + int BPos; \ + ChColor Color = ColorNormal; \ + int i; \ + int len = Line->Count; \ + char *p = Line->Chars; \ + int NC = 0, C = 0; \ + int TabSize = BFI(BF, BFI_TabSize); \ + int ExpandTabs = BFI(BF, BFI_ExpandTabs); + +//#define HILIT_VARS2() +// int len1 = len; +// char *last = p + len1 - 1; + +#define IF_TAB() \ + if (*p == '\t' && ExpandTabs) { \ + NC = NextTab(C, TabSize); \ + if (StateMap) StateMap[i] = hsState(State);\ + if (B) MoveChar(B, C - Pos, Width, ' ', Color, NC - C);\ + if (BFI(BF, BFI_ShowTabs)) ColorChar();\ + i++,len--,p++;\ + C = NC;\ + continue;\ + } + +#define CK_MAXLEN 32 + +typedef struct { + int TotalCount; + int count[CK_MAXLEN]; + char *key[CK_MAXLEN]; +} ColorKeywords; + +struct HTrans { + char *match; + int matchLen; + long matchFlags; + int nextState; + int color; + + void InitTrans(); +}; + +struct HState { + int transCount; + int firstTrans; + int color; + + ColorKeywords keywords; + char *wordChars; + long options; + int nextKwdMatchedState; + int nextKwdNotMatchedState; + int nextKwdNoCharState; + + void InitState(); + int GetHilitWord(int len, char *str, ChColor &clr); +}; + +class HMachine { +public: + int stateCount; + int transCount; + HState *state; + HTrans *trans; + + HMachine(); + ~HMachine(); + void AddState(HState &aState); + void AddTrans(HTrans &aTrans); + + HState *LastState() { return state + stateCount - 1; } +}; + +class EColorize { +public: + char *Name; + EColorize *Next; + EColorize *Parent; + int SyntaxParser; + ColorKeywords Keywords; // keywords to highlight + HMachine *hm; + ChColor Colors[COUNT_CLR]; + + EColorize(const char *AName, const char *AParent); + ~EColorize(); + + int SetColor(int clr, const char *value); +}; + +extern EColorize *Colorizers; +EColorize *FindColorizer(const char *AName); + +SyntaxProc GetHilitProc(int id); + +int IsState(hsState *Buf, hsState State, int Len); +int LookAt(EBuffer *B, int Row, unsigned int Pos, const char *What, hsState State, int NoWord = 1, int CaseInsensitive = 0); +inline int LookAtNoCase(EBuffer *B, int Row, unsigned int Pos, const char *What, hsState State, int NoWord = 1) +{ return LookAt(B, Row, Pos, What, State, NoWord, 1); } + +#endif + +#endif diff --git a/src/c_history.cpp b/src/c_history.cpp new file mode 100644 index 0000000..ec206d4 --- /dev/null +++ b/src/c_history.cpp @@ -0,0 +1,260 @@ +/* c_history.cpp + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#include "fte.h" + +#ifdef CONFIG_HISTORY + +#define HISTORY_VER "FTE History 1\n" + +char HistoryFileName[256] = ""; + +static FPosHistory **FPHistory = 0; +static int FPHistoryCount = 0; + +static InputHistory inputHistory = { 0, 0, 0 }; + +void ClearHistory() { /*FOLD00*/ + + // free filenames from all entries + while(FPHistoryCount--) + { + free(FPHistory[FPHistoryCount]->FileName); + free(FPHistory[FPHistoryCount]); + } + + // free history list + free(FPHistory); + + // free input history + { + while(inputHistory.Count--) + { + free(inputHistory.Line[inputHistory.Count]); + } + free(inputHistory.Line); + free(inputHistory.Id); + } +} + +int SaveHistory(char *FileName) { /*FOLD00*/ + FILE *fp; + + fp = fopen(FileName, "w"); + if (fp == 0) + return 0; + setvbuf(fp, FileBuffer, _IOFBF, sizeof(FileBuffer)); + fprintf(fp, HISTORY_VER); + if (FPHistory) { // file position history + int i; + for (i = 0; i < FPHistoryCount; i++) + fprintf(fp, "F|%d|%d|%s\n", + FPHistory[i]->Row, + FPHistory[i]->Col, + FPHistory[i]->FileName); + } + { // input history + for (int i = 0; i < inputHistory.Count; i++) { + fprintf(fp, "I|%d|%s\n", inputHistory.Id[i], inputHistory.Line[i]); + } + } + fclose(fp); + return 1; +} + +int LoadHistory(char *FileName) { /*fold00*/ + FILE *fp; + char line[2048]; + char *p, *e; + + fp = fopen(FileName, "r"); + if (fp == 0) + return 0; + + setvbuf(fp, FileBuffer, _IOFBF, sizeof(FileBuffer)); + + if (fgets(line, sizeof(line), fp) == 0 || + strcmp(line, HISTORY_VER) != 0) + { + fclose(fp); + return 0; + } + while (fgets(line, sizeof(line), fp) != 0) { + if (line[0] == 'F' && line[1] == '|') { // input history + int r, c; + p = line + 2; + r = strtol(p, &e, 10); + if (e == p) + break; + if (*e == '|') + e++; + else + break; + c = strtol(p = e, &e, 10); + if (e == p) + break; + if (*e == '|') + e++; + else + break; + e = strchr(p = e, '\n'); + if (e == 0) + break; + *e = 0; + if (UpdateFPos(p, r, c) == 0) + break; + } else if (line[0] == 'I' && line[1] == '|') { // file position history + int i; + + p = line + 2; + i = strtol(p, &e, 10); + if (e == p) + break; + if (*e == '|') + e++; + else + break; + e = strchr(p = e, '\n'); + if (e == 0) + break; + *e = 0; + AddInputHistory(i, p); + } + } + fclose(fp); + return 1; +} + +int UpdateFPos(char *FileName, int Row, int Col) { /*fold00*/ + int L = 0, R = FPHistoryCount, M, N; + FPosHistory *fp, **NH; + int cmp; + + if (FPHistory != 0) { + while (L < R) { + M = (L + R) / 2; + cmp = filecmp(FileName, FPHistory[M]->FileName); + if (cmp == 0) { + FPHistory[M]->Row = Row; + FPHistory[M]->Col = Col; + return 1; + } else if (cmp < 0) { + R = M; + } else { + L = M + 1; + } + } + } else { + FPHistoryCount = 0; + L = 0; + } + assert(L >= 0 && L <= FPHistoryCount); + fp = (FPosHistory *)malloc(sizeof(FPosHistory)); + if (fp == 0) + return 0; + fp->Row = Row; + fp->Col = Col; + fp->FileName = strdup(FileName); + if (fp->FileName == 0) { + free(fp); + return 0; + } + + N = 64; + while (N <= FPHistoryCount) N *= 2; + NH = (FPosHistory **)realloc((void *)FPHistory, N * sizeof(FPosHistory *)); + if (NH == 0) + { + free(fp->FileName); + free(fp); + return 0; + } + + FPHistory = NH; + + if (L < FPHistoryCount) + memmove(FPHistory + L + 1, + FPHistory + L, + (FPHistoryCount - L) * sizeof(FPosHistory *)); + FPHistory[L] = fp; + FPHistoryCount++; + return 1; +} + +int RetrieveFPos(char *FileName, int &Row, int &Col) { /*FOLD00*/ + int L = 0, R = FPHistoryCount, M; + int cmp; + + if (FPHistory == 0) + return 0; + + while (L < R) { + M = (L + R) / 2; + cmp = filecmp(FileName, FPHistory[M]->FileName); + if (cmp == 0) { + Row = FPHistory[M]->Row; + Col = FPHistory[M]->Col; + return 1; + } else if (cmp < 0) { + R = M; + } else { + L = M + 1; + } + } + return 0; +} + +int AddInputHistory(int Id, char *String) { /*fold00*/ + if (inputHistory.Count < MAX_INPUT_HIST) { + inputHistory.Count++; + inputHistory.Line = (char **) realloc((void *) inputHistory.Line, + inputHistory.Count * sizeof(char *)); + inputHistory.Id = (int *) realloc((void *) inputHistory.Id, + inputHistory.Count * sizeof(int *)); + } else { + free(inputHistory.Line[inputHistory.Count - 1]); + } + memmove(inputHistory.Line + 1, + inputHistory.Line, + (inputHistory.Count - 1) * sizeof(char *)); + memmove(inputHistory.Id + 1, + inputHistory.Id, + (inputHistory.Count - 1) * sizeof(int *)); + inputHistory.Id[0] = Id; + inputHistory.Line[0] = strdup(String); + return 1; +} + +int CountInputHistory(int Id) { /*fold00*/ + int i, c = 0; + + for (i = 0; i < inputHistory.Count; i++) + if (inputHistory.Id[i] == Id) c++; + return c; +} + +int GetInputHistory(int Id, char *String, int len, int Nth) { /*fold00*/ + int i = 0; + + assert(len > 0); + + while (i < inputHistory.Count) { + if (inputHistory.Id[i] == Id) { + Nth--; + if (Nth == 0) { + strncpy(String, inputHistory.Line[i], len); + String[len - 1] = 0; + return 1; + } + } + i++; + } + return 0; +} +#endif diff --git a/src/c_history.h b/src/c_history.h new file mode 100644 index 0000000..3868495 --- /dev/null +++ b/src/c_history.h @@ -0,0 +1,64 @@ +/* c_history.h + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#ifndef __FPOSHIST_H__ +#define __FPOSHIST_H__ + +#ifdef CONFIG_HISTORY + +#ifdef UNIX +#define HISTORY_NAME ".fte-history" +#else +#define HISTORY_NAME "fte.his" +#endif + +typedef struct { + char *FileName; + int Row, Col; +} FPosHistory; + +#define MAX_INPUT_HIST 128 + +typedef struct { + int Count; + char **Line; + int *Id; +} InputHistory; + +extern char HistoryFileName[256]; + + +void ClearHistory(); +int SaveHistory(char *FileName); +int LoadHistory(char *FileName); + +int UpdateFPos(char *FileName, int Row, int Col); +int RetrieveFPos(char *FileName, int &Row, int &Col); + +int AddInputHistory(int Id, char *String); +int CountInputHistory(int Id); +int GetInputHistory(int Id, char *String, int maxlen, int Nth); + +/* history values */ +#define HIST_DEFAULT 0 +#define HIST_PATH 1 +#define HIST_SEARCH 2 +#define HIST_POSITION 3 +#define HIST_SETUP 4 +#define HIST_SHELL 5 +#define HIST_COMPILE 6 +#define HIST_SEARCHOPT 7 +#define HIST_BOOKMARK 8 +#define HIST_REGEXP 9 +#define HIST_TRANS 10 +#define HIST_TAGFILES 11 + +#endif + +#endif diff --git a/src/c_mode.cpp b/src/c_mode.cpp new file mode 100644 index 0000000..cc7f8d6 --- /dev/null +++ b/src/c_mode.cpp @@ -0,0 +1,133 @@ +/* c_mode.cpp + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#include "fte.h" + +EBufferFlags DefaultBufferFlags = { + { + 1, // AutoIndent + 1, // InsertOn + 0, // DrawOn + 1, // HilitOn + 1, // ExpandTabs + 0, // Trim + 8, // TabSize + HILIT_PLAIN, // HilitMode + INDENT_PLAIN, // IndentMode + 0, // ShowTab + 10, // LineChar +#if !defined(UNIX) + 13, // StripChar +#else + -1, +#endif + 1, // AddLine +#if !defined(UNIX) + 1, // AddStrip +#else + 0, +#endif + 0, // ForceNewLine + 0, // HardMode + 1, // UndoRedo + 0, // ReadOnly + 0, // AutoSave + 1, // KeepBackups + -1, // LoadMargin + 256, // Max Undo/Redo Commands + 1, // MatchCase + 0, // BackKillTab + 0, // DelKillTab + 1, // BackSpUnindent + 0, // SpaceTabs + 1, // IndentWTabs + 1, // Wrap.LeftMargin + 72, // Wrap.RightMargin + 1, // See Thru Sel + 0, // WordWrap + 0, // ShowMarkers + 1, // CursorThroughTabs + 0, // Save Folds + 0, // MultiLineHilit + 0, // AutoHilitParen + 0, // Abbreviations + 0, // BackSpKillBlock + 0, // DeleteKillBlock + 1, // PersistentBlocks + 0, // InsertKillBlock + 0, // UndoMoves +#ifdef UNIX + 0, // DetectLineSep +#else + 1, +#endif + 0 // trim on save + }, + { + 0, // Routine Regexp + 0, // DefFindOpt + 0, // DefFindReplaceOpt + 0, // comment start (folds) + 0, // comment end (folds) + 0, // filename rx + 0, // firstline rx + 0 // compile command + } +}; + +EMode *GetModeForName(const char *FileName) { + // char ext[10]; + // char *p; + int l, i; + EMode *m; + RxMatchRes RM; + char buf[81]; + int fd; + + m = Modes; + while (m) { + if (m->MatchNameRx) + if (RxExec(m->MatchNameRx, + FileName, strlen(FileName), FileName, + &RM) == 1) + return m; + if (m->fNext == 0) break; + m = m->fNext; + } + + fd = open(FileName, O_RDONLY); + if (fd != -1) { + l = read(fd, buf, 80); + close(fd); + if (l > 0) { + buf[l] = 0; + for (i = 0; i < l; i++) { + if (buf[i] == '\n') { + buf[i] = 0; + l = i; + break; + } + } + m = Modes; + while (m) { + if (m->MatchLineRx) + if (RxExec(m->MatchLineRx, buf, l, buf, &RM) == 1) + return m; + if (m->fNext == 0) break; + m = m->fNext; + } + } + } + + if ((m = FindMode(DefaultModeName)) != 0) return m; + + m = Modes; + while (m && m->fNext) m = m->fNext; + return m; +} diff --git a/src/c_mode.h b/src/c_mode.h new file mode 100644 index 0000000..7e9945c --- /dev/null +++ b/src/c_mode.h @@ -0,0 +1,262 @@ +/* c_mode.h + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#ifndef __EMODE_H__ +#define __EMODE_H__ + +#define CMD_EXT 0x1000 // max 4096 internal commands, check cfte.cpp + +#define CONTEXT_NONE 0 +#define CONTEXT_FILE 1 +#define CONTEXT_DIRECTORY 2 +#define CONTEXT_MESSAGES 3 +#define CONTEXT_SHELL 4 +#define CONTEXT_INPUT 5 +#define CONTEXT_CHOICE 6 +#define CONTEXT_LIST 7 +#define CONTEXT_CHAR 8 +#define CONTEXT_BUFFERS 9 +#define CONTEXT_ROUTINES 10 +#define CONTEXT_MAPVIEW 11 + +typedef unsigned char ChColor; + +#define HILIT_PLAIN 0 +#define HILIT_C 1 +#define HILIT_HTML 2 +#define HILIT_MAKE 3 +#define HILIT_REXX 4 +#define HILIT_DIFF 5 +#define HILIT_IPF 6 +#define HILIT_PERL 7 +#define HILIT_MERGE 8 +#define HILIT_ADA 9 +#define HILIT_MSG 10 +#define HILIT_SH 11 +#define HILIT_PASCAL 12 +#define HILIT_TEX 13 +#define HILIT_FTE 14 +#define HILIT_CATBS 15 +#define HILIT_SIMPLE 16 + +#define INDENT_PLAIN 0 +#define INDENT_C 1 +#define INDENT_REXX 2 +#define INDENT_SIMPLE 3 + +#define BFI_AutoIndent 0 +#define BFI_Insert 1 +#define BFI_DrawOn 2 +#define BFI_HilitOn 3 +#define BFI_ExpandTabs 4 +#define BFI_Trim 5 +#define BFI_TabSize 6 +#define BFI_ShowTabs 9 +#define BFI_HardMode 15 +#define BFI_Undo 16 +#define BFI_ReadOnly 17 +#define BFI_AutoSave 18 +#define BFI_KeepBackups 19 +#define BFI_MatchCase 22 +#define BFI_BackSpKillTab 23 +#define BFI_DeleteKillTab 24 +#define BFI_BackSpUnindents 25 +#define BFI_SpaceTabs 26 +#define BFI_IndentWithTabs 27 +#define BFI_SeeThruSel 30 +#define BFI_ShowMarkers 32 +#define BFI_CursorThroughTabs 33 +#define BFI_MultiLineHilit 35 + +#define BFI_WordWrap 31 +#define BFI_LeftMargin 28 +#define BFI_RightMargin 29 + +#define BFI_Colorizer 7 +#define BFI_IndentMode 8 + +#define BFI_LineChar 10 +#define BFI_StripChar 11 +#define BFI_AddLF 12 +#define BFI_AddCR 13 +#define BFI_ForceNewLine 14 +#define BFI_LoadMargin 20 +#define BFI_SaveFolds 34 + +#define BFI_UndoLimit 21 + +#define BFI_AutoHilitParen 36 +#define BFI_Abbreviations 37 +#define BFI_BackSpKillBlock 38 +#define BFI_DeleteKillBlock 39 +#define BFI_PersistentBlocks 40 +#define BFI_InsertKillBlock 41 +#define BFI_EventMap 42 +#define BFI_UndoMoves 43 +#define BFI_DetectLineSep 44 +#define BFI_TrimOnSave 45 + +#define BFI_COUNT 46 + +#define BFS_RoutineRegexp (0 | 256) +#define BFS_DefFindOpt (1 | 256) +#define BFS_DefFindReplaceOpt (2 | 256) +#define BFS_CommentStart (3 | 256) +#define BFS_CommentEnd (4 | 256) +#define BFS_FileNameRx (5 | 256) +#define BFS_FirstLineRx (6 | 256) +#define BFS_CompileCommand (7 | 256) + +#define BFS_COUNT 8 + +#define BFS_WordChars (100 | 256) // ext +#define BFS_CapitalChars (101 | 256) + +#define BFI(y,x) ((y)->Flags.num[(x) & 0xFF]) +#define BFI_SET(y,x,v) ((y)->Flags.num[(x) & 0xFF]=(v)) +#define BFS(y,x) ((y)->Flags.str[(x) & 0xFF]) + +#define WSETBIT(x,y,z) \ + ((x)[(unsigned char)(y) >> 3] = char((z) ? \ + ((x)[(unsigned char)(y) >> 3] | (1 << ((unsigned char)(y) & 0x7))) : \ + ((x)[(unsigned char)(y) >> 3] & ~(1 << ((unsigned char)(y) & 0x7))))) + +#define WGETBIT(x,y) \ + (((x)[(unsigned char)(y) / 8] & (1 << ((unsigned char)(y) % 8))) ? 1 : 0) + +typedef struct { + int num[BFI_COUNT]; + char *str[BFS_COUNT]; + char WordChars[32]; + char CapitalChars[32]; +} EBufferFlags; + +extern EBufferFlags DefaultBufferFlags; + +/* globals */ +#define FLAG_C_Indent 1 +#define FLAG_C_BraceOfs 2 +#define FLAG_REXX_Indent 3 +#define FLAG_ScreenSizeX 6 +#define FLAG_ScreenSizeY 7 +#define FLAG_CursorInsertStart 8 +#define FLAG_CursorInsertEnd 9 +#define FLAG_CursorOverStart 10 +#define FLAG_CursorOverEnd 11 +#define FLAG_SysClipboard 12 +#define FLAG_ShowHScroll 13 +#define FLAG_ShowVScroll 14 +#define FLAG_ScrollBarWidth 15 +#define FLAG_SelectPathname 16 +#define FLAG_C_CaseOfs 18 +#define FLAG_DefaultModeName 19 +#define FLAG_CompletionFilter 20 +#define FLAG_ShowMenuBar 22 +#define FLAG_C_CaseDelta 23 +#define FLAG_C_ClassOfs 24 +#define FLAG_C_ClassDelta 25 +#define FLAG_C_ColonOfs 26 +#define FLAG_C_CommentOfs 27 +#define FLAG_C_CommentDelta 28 +#define FLAG_OpenAfterClose 30 +#define FLAG_PrintDevice 31 +#define FLAG_CompileCommand 32 +#define FLAG_REXX_Do_Offset 33 +#define FLAG_KeepHistory 34 +#define FLAG_LoadDesktopOnEntry 35 +#define FLAG_SaveDesktopOnExit 36 +#define FLAG_WindowFont 37 +#define FLAG_KeepMessages 38 +#define FLAG_ScrollBorderX 39 +#define FLAG_ScrollBorderY 40 +#define FLAG_ScrollJumpX 41 +#define FLAG_ScrollJumpY 42 +#define FLAG_ShowToolBar 43 +#define FLAG_GUIDialogs 44 +#define FLAG_PMDisableAccel 45 +#define FLAG_SevenBit 46 +#define FLAG_WeirdScroll 47 +#define FLAG_LoadDesktopMode 48 +#define FLAG_HelpCommand 49 +#define FLAG_C_FirstLevelIndent 50 +#define FLAG_C_FirstLevelWidth 51 +#define FLAG_C_Continuation 52 +#define FLAG_C_ParenDelta 32 + +#define EM_MENUS 2 +#define EM_MainMenu 0 +#define EM_LocalMenu 1 + +#define COL_SyntaxParser 1 + +#define CLR_Normal 0 +#define CLR_Keyword 1 +#define CLR_String 2 +#define CLR_Comment 3 +#define CLR_CPreprocessor 4 +#define CLR_Regexp 5 +#define CLR_Header 6 +#define CLR_Quotes 7 +#define CLR_Number 8 +#define CLR_HexNumber 9 +#define CLR_OctalNumber 10 +#define CLR_FloatNumber 11 +#define CLR_Function 12 +#define CLR_Command 13 +#define CLR_Tag 14 +#define CLR_Punctuation 15 +#define CLR_New 16 +#define CLR_Old 17 +#define CLR_Changed 18 +#define CLR_Control 19 +#define CLR_Separator 20 +#define CLR_Variable 21 +#define CLR_Symbol 22 +#define CLR_Directive 23 +#define CLR_Label 24 +#define CLR_Special 25 +#define CLR_QuoteDelim 26 +#define CLR_RegexpDelim 27 + +#define COUNT_CLR 28 + +#define MATCH_MUST_BOL 0x0001 +#define MATCH_MUST_BOLW 0x0002 +#define MATCH_MUST_EOL 0x0004 +#define MATCH_MUST_EOLW 0x0008 +#define MATCH_NO_CASE 0x0010 +#define MATCH_SET 0x0020 +#define MATCH_NOTSET 0x0040 +#define MATCH_QUOTECH 0x0100 +#define MATCH_QUOTEEOL 0x0200 +#define MATCH_NOGRAB 0x0400 +#define MATCH_NEGATE 0x0800 +#define MATCH_TAGASNEXT 0x1000 + +#define ACTION_NXSTATE 0x0001 + +#define STATE_NOCASE 0x0001 +#define STATE_TAGASNEXT 0x0002 +#define STATE_NOGRAB 0x0004 + +typedef enum { + mvFilePath = 1, /* directory + name + extension */ + mvFileName, /* name + extension */ + mvFileDirectory, /* directory + '/' */ + mvFileBaseName, /* without the last extension */ + mvFileExtension, /* the last one */ + mvCurDirectory, + mvCurRow, + mvCurCol, + mvChar, + mvWord, + mvLine +} MacroVariable; + +#endif diff --git a/src/cfte.cpp b/src/cfte.cpp new file mode 100644 index 0000000..ac76daf --- /dev/null +++ b/src/cfte.cpp @@ -0,0 +1,1789 @@ +/* cfte.cpp + * + * Copyright (c) 1994-1997, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ftever.h" +#include "sysdep.h" +#include "feature.h" +#include "c_fconfig.h" +#include "s_files.h" +#include "c_mode.h" + +#define slen(s) ((s) ? (strlen(s) + 1) : 0) + +typedef struct { + char *Name; +} ExMacro; + +unsigned int CMacros = 0; +ExMacro *Macros = 0; + +FILE *output = 0; +int lntotal = 0; +long offset = -1; +long pos = 0; +char XTarget[MAXPATH] = ""; +char StartDir[MAXPATH] = ""; + +#include "c_commands.h" +#include "c_cmdtab.h" + +typedef struct _CurPos { + int sz; + char *a; + char *c; + char *z; + int line; + const char *name; // filename +} CurPos; + +void cleanup(int xerrno) { + if (output) + fclose(output); + if (XTarget[0] != 0) + unlink(XTarget); + exit (xerrno); +} + +void Fail(CurPos &cp, const char *s, ...) { + va_list ap; + char msgbuf[1024]; + + va_start(ap, s); + vsprintf(msgbuf, s, ap); + va_end(ap); + + fprintf(stderr, "%s:%d: Error: %s\n", cp.name, cp.line, msgbuf); + cleanup(1); +} + +int LoadFile(const char *WhereName, const char *CfgName, int Level = 1); +void DefineWord(const char *w); +void PutObject(CurPos &cp, int xtag, int xlen, void *obj) { + unsigned char tag = (unsigned char)xtag; + unsigned short len = (unsigned short)xlen; + unsigned char l[2]; + + l[0] = len & 0xFF; + l[1] = (len >> 8) & 0xFF; + + if (fwrite(&tag, 1, 1, output) != 1 || + fwrite(l, 2, 1, output) != 1 || + fwrite(obj, 1, len, output) != len) + { + Fail(cp, "Disk full!"); + } + pos += 1 + 2 + len; + if (offset != -1 && pos >= offset) { + Fail(cp, "Error location found at %ld", pos); + } +} + +void PutNull(CurPos &cp, int xtag) { + PutObject(cp, xtag, 0, 0); +} + +void PutString(CurPos &cp, int xtag, char *str) { + PutObject(cp, xtag, slen(str), str); +} + +void PutNumber(CurPos &cp, int xtag, long num) { + unsigned long l = num; + unsigned char b[4]; + + b[0] = (unsigned char)(l & 0xFF); + b[1] = (unsigned char)((l >> 8) & 0xFF); + b[2] = (unsigned char)((l >> 16) & 0xFF); + b[3] = (unsigned char)((l >> 24) & 0xFF); + PutObject(cp, xtag, 4, &b); +} + +int main(int argc, char **argv) { + char Source[MAXPATH]; + char Target[MAXPATH]; + char *p = argv[1]; + int n = 1; + + fprintf(stderr, PROG_CFTE " " VERSION "\n" COPYRIGHT "\n"); + if (argc < 2 || argc > 4) { + fprintf(stderr, "Usage: " PROG_CFTE " [-o] " +#ifndef UNIX + "config/" +#endif + "main.fte [fte-new.cnf]\n"); + exit(1); + } + + DefineWord("OS_" +#if defined(OS2) + "OS2" +#elif defined(UNIX) + "UNIX" +#elif defined(NT) + "NT" +#elif defined(DOSP32) + "DOS32" +#endif + ); + + if (strncmp(p, "-o", 2) == 0) { + p += 2; + offset = atol(p); + n++; + } + if (n == 1 && argc == 4) { + fprintf(stderr, "Invalid option '%s'\n", argv[1]); + exit(1); + } + strcpy(Source, argv[n++]); + strcpy(Target, "fte-new.cnf"); + if (n < argc) + strcpy(Target, argv[n++]); + + JustDirectory(Target, XTarget); + Slash(XTarget, 1); + sprintf(XTarget + strlen(XTarget), "cfte%ld.tmp", (long)getpid()); + output = fopen(XTarget, "wb"); + if (output == 0) { + fprintf(stderr, "Cannot create '%s', errno=%d!\n", XTarget, errno); + cleanup(1); + } + + unsigned char b[4]; + + b[0] = b[1] = b[2] = b[3] = 0; + + if (fwrite(b, sizeof(b), 1, output) != 1) { + fprintf(stderr, "Disk full!"); + cleanup(1); + } + + unsigned long l = VERNUM; + + b[0] = (unsigned char)(l & 0xFF); + b[1] = (unsigned char)((l >> 8) & 0xFF); + b[2] = (unsigned char)((l >> 16) & 0xFF); + b[3] = (unsigned char)((l >> 24) & 0xFF); + + if (fwrite(b, 4, 1, output) != 1) { + fprintf(stderr, "Disk full!"); + cleanup(1); + } + pos = 2 * 4; + + fprintf(stderr, "Compiling to '%s'\n", Target); + /*{ + char PrevDir[MAXPATH]; + sprintf(PrevDir, "%s/..", Target); + ExpandPath(PrevDir, StartDir); + Slash(StartDir, 1); + }*/ + + ExpandPath("." +#ifdef UNIX + "." +#endif + , StartDir); + Slash(StartDir, 1); + + { + CurPos cp; + char FSource[MAXPATH]; + + if (ExpandPath(Source, FSource) != 0) { + fprintf(stderr, "Could not expand path %s\n", Source); + exit(1); + } + + cp.sz = 0; + cp.c = 0; + cp.a = cp.c = 0; + cp.z = cp.a + cp.sz; + cp.line = 0; + cp.name = ""; + + PutString(cp, CF_STRING, FSource); + } + + if (LoadFile(StartDir, Source, 0) != 0) { + fprintf(stderr, "\nCompile failed\n"); + cleanup(1); + } + + l = CONFIG_ID; + b[0] = (unsigned char)(l & 0xFF); + b[1] = (unsigned char)((l >> 8) & 0xFF); + b[2] = (unsigned char)((l >> 16) & 0xFF); + b[3] = (unsigned char)((l >> 24) & 0xFF); + fseek(output, 0, SEEK_SET); + fwrite(b, 4, 1, output); + fclose(output); + + if (unlink(Target) != 0 && errno != ENOENT) { + fprintf(stderr, "Remove of '%s' failed, result left in %s, errno=%d\n", + Target, XTarget, errno); + exit(1); + } + + if (rename(XTarget, Target) != 0) { + fprintf(stderr, "Rename of '%s' to '%s' failed, errno=%d\n", + XTarget, Target, errno); + exit(1); + } + + fprintf(stderr, "\nDone.\n"); + return 0; +} + +#define MODE_BFI(x) { #x, BFI_##x } +#define MODE_BFS(x) { #x, BFS_##x } +#define MODE_FLG(x) { #x, FLAG_##x } +#define EVENT_FLG(x) { #x, EM_##x } +#define COLORIZE_FLG(x) { #x, COL_##x } +#define HILIT_CLR(x) { #x, CLR_##x } + +typedef struct _OrdLookup { + const char *Name; + int num; +} OrdLookup; + +OrdLookup mode_num[] = { +MODE_BFI(AutoIndent), +MODE_BFI(Insert), +MODE_BFI(DrawOn), +MODE_BFI(HilitOn), +MODE_BFI(ExpandTabs), +MODE_BFI(Trim), +MODE_BFI(TabSize), +MODE_BFI(ShowTabs), +MODE_BFI(LineChar), +MODE_BFI(StripChar), +MODE_BFI(AddLF), +MODE_BFI(AddCR), +MODE_BFI(ForceNewLine), +MODE_BFI(HardMode), +MODE_BFI(Undo), +MODE_BFI(ReadOnly), +MODE_BFI(AutoSave), +MODE_BFI(KeepBackups), +MODE_BFI(LoadMargin), +MODE_BFI(UndoLimit), +MODE_BFI(MatchCase), +MODE_BFI(BackSpKillTab), +MODE_BFI(DeleteKillTab), +MODE_BFI(BackSpUnindents), +MODE_BFI(SpaceTabs), +MODE_BFI(IndentWithTabs), +MODE_BFI(LeftMargin), +MODE_BFI(RightMargin), +MODE_BFI(SeeThruSel), +MODE_BFI(WordWrap), +MODE_BFI(ShowMarkers), +MODE_BFI(CursorThroughTabs), +MODE_BFI(SaveFolds), +MODE_BFI(MultiLineHilit), +MODE_BFI(AutoHilitParen), +MODE_BFI(Abbreviations), +MODE_BFI(BackSpKillBlock), +MODE_BFI(DeleteKillBlock), +MODE_BFI(PersistentBlocks), +MODE_BFI(InsertKillBlock), +MODE_BFI(UndoMoves), +MODE_BFI(DetectLineSep), +MODE_BFI(TrimOnSave), +{ 0, 0 }, +}; + +OrdLookup mode_string[] = { +MODE_BFI(Colorizer), +MODE_BFI(IndentMode), +MODE_BFS(RoutineRegexp), +MODE_BFS(DefFindOpt), +MODE_BFS(DefFindReplaceOpt), +MODE_BFS(CommentStart), +MODE_BFS(CommentEnd), +MODE_BFS(WordChars), +MODE_BFS(CapitalChars), +MODE_BFS(FileNameRx), +MODE_BFS(FirstLineRx), +MODE_BFS(CompileCommand), +MODE_BFI(EventMap), +{ 0, 0 }, +}; + +OrdLookup global_num[] = { +#ifdef CONFIG_INDENT_C +MODE_FLG(C_Indent), +MODE_FLG(C_BraceOfs), +MODE_FLG(C_CaseOfs), +MODE_FLG(C_CaseDelta), +MODE_FLG(C_ClassOfs), +MODE_FLG(C_ClassDelta), +MODE_FLG(C_ColonOfs), +MODE_FLG(C_CommentOfs), +MODE_FLG(C_CommentDelta), +MODE_FLG(C_FirstLevelWidth), +MODE_FLG(C_FirstLevelIndent), +MODE_FLG(C_Continuation), +MODE_FLG(C_ParenDelta), +#endif +#ifdef CONFIG_INDENT_REXX +MODE_FLG(REXX_Indent), +MODE_FLG(REXX_Do_Offset), +#endif +MODE_FLG(ScreenSizeX), +MODE_FLG(ScreenSizeY), +MODE_FLG(CursorInsertStart), +MODE_FLG(CursorInsertEnd), +MODE_FLG(CursorOverStart), +MODE_FLG(CursorOverEnd), +MODE_FLG(SysClipboard), +MODE_FLG(OpenAfterClose), +MODE_FLG(ShowVScroll), +MODE_FLG(ShowHScroll), +MODE_FLG(ScrollBarWidth), +MODE_FLG(SelectPathname), +MODE_FLG(ShowToolBar), +MODE_FLG(ShowMenuBar), +MODE_FLG(KeepHistory), +MODE_FLG(LoadDesktopOnEntry), +MODE_FLG(SaveDesktopOnExit), +MODE_FLG(KeepMessages), +MODE_FLG(ScrollBorderX), +MODE_FLG(ScrollBorderY), +MODE_FLG(ScrollJumpX), +MODE_FLG(ScrollJumpY), +MODE_FLG(GUIDialogs), +MODE_FLG(PMDisableAccel), +MODE_FLG(SevenBit), +MODE_FLG(WeirdScroll), +MODE_FLG(LoadDesktopMode), +{ 0, 0 }, +}; + +OrdLookup global_string[] = { +MODE_FLG(DefaultModeName), +MODE_FLG(CompletionFilter), +MODE_FLG(PrintDevice), +MODE_FLG(CompileCommand), +MODE_FLG(WindowFont), +MODE_FLG(HelpCommand), +{ 0, 0 }, +}; + +OrdLookup event_string[] = { +EVENT_FLG(MainMenu), +EVENT_FLG(LocalMenu), +{ 0, 0 }, +}; + +OrdLookup colorize_string[] = { +COLORIZE_FLG(SyntaxParser), +{ 0, 0 }, +}; + +OrdLookup hilit_colors[] = { +HILIT_CLR(Normal), +HILIT_CLR(Keyword), +HILIT_CLR(String), +HILIT_CLR(Comment), +HILIT_CLR(CPreprocessor), +HILIT_CLR(Regexp), +HILIT_CLR(Header), +HILIT_CLR(Quotes), +HILIT_CLR(Number), +HILIT_CLR(HexNumber), +HILIT_CLR(OctalNumber), +HILIT_CLR(FloatNumber), +HILIT_CLR(Function), +HILIT_CLR(Command), +HILIT_CLR(Tag), +HILIT_CLR(Punctuation), +HILIT_CLR(New), +HILIT_CLR(Old), +HILIT_CLR(Changed), +HILIT_CLR(Control), +HILIT_CLR(Separator), +HILIT_CLR(Variable), +HILIT_CLR(Symbol), +HILIT_CLR(Directive), +HILIT_CLR(Label), +HILIT_CLR(Special), +HILIT_CLR(QuoteDelim), +HILIT_CLR(RegexpDelim), +{ 0, 0 }, +}; + +int Lookup(OrdLookup *where, char *what) { + int i; + + for (i = 0; where[i].Name != 0; i++) { + if (strcmp(what, where[i].Name) == 0) + return where[i].num; + } +// fprintf(stderr, "\nBad name: %s (i = %d)\n", what, i); + return -1; +} + +#define P_EOF 0 // end of file +#define P_SYNTAX 1 // unknown +#define P_WORD 2 // a-zA-Z_ +#define P_NUMBER 3 // 0-9 +#define P_STRING 4 // "'` +#define P_ASSIGN 5 // = +#define P_EOS 6 // ; +#define P_KEYSPEC 7 // [] +#define P_OPENBRACE 8 // { +#define P_CLOSEBRACE 9 // } +#define P_COLON 10 // : +#define P_COMMA 11 // , +#define P_QUEST 12 +#define P_VARIABLE 13 // $ +#define P_DOT 14 // . (concat) + +#define K_UNKNOWN 0 +#define K_MODE 1 +#define K_KEY 2 +#define K_COLOR 3 +#define K_KEYWORD 4 +#define K_OBJECT 5 +#define K_MENU 6 +#define K_ITEM 7 +#define K_SUBMENU 8 +#define K_COMPILERX 9 +#define K_EXTERN 10 +#define K_INCLUDE 11 +#define K_SUB 12 +#define K_EVENTMAP 13 +#define K_COLORIZE 14 +#define K_ABBREV 15 +#define K_HSTATE 16 +#define K_HTRANS 17 +#define K_HWORDS 18 +#define K_SUBMENUCOND 19 +#define K_HWTYPE 20 +#define K_COLPALETTE 21 + +typedef char Word[64]; + +OrdLookup CfgKW[] = { +{ "mode", K_MODE }, +{ "eventmap", K_EVENTMAP }, +{ "key", K_KEY }, +{ "color", K_COLOR }, +{ "color_palette", K_COLPALETTE }, +{ "keyword", K_KEYWORD }, +{ "object", K_OBJECT }, +{ "menu", K_MENU }, +{ "item", K_ITEM }, +{ "submenu", K_SUBMENU }, +{ "CompileRx", K_COMPILERX }, +{ "extern", K_EXTERN }, +{ "include", K_INCLUDE }, +{ "sub", K_SUB }, +{ "colorize", K_COLORIZE }, +{ "abbrev", K_ABBREV }, +{ "h_state", K_HSTATE }, +{ "h_trans", K_HTRANS }, +{ "h_words", K_HWORDS }, +{ "h_wtype", K_HWTYPE }, +{ "submenucond", K_SUBMENUCOND }, +{ 0, 0 }, +}; + +OrdLookup CfgVar[] = { + { "FilePath", mvFilePath }, + { "FileName", mvFileName }, + { "FileDirectory", mvFileDirectory }, + { "FileBaseName", mvFileBaseName }, + { "FileExtension", mvFileExtension }, + { "CurDirectory", mvCurDirectory }, + { "CurRow", mvCurRow, }, + { "CurCol", mvCurCol }, + { "Char", mvChar }, + { "Word", mvWord }, + { "Line", mvLine }, + { 0, 0 }, +}; + +char **words = 0; +unsigned int wordCount = 0; + +int DefinedWord(const char *w) { + if (words == 0 || wordCount == 0) + return 0; + for (unsigned int i = 0; i < wordCount; i++) + if (strcmp(w, words[i]) == 0) + return 1; + return 0; +} + +void DefineWord(const char *w) { + if (!w || !w[0]) + return ; + if (!DefinedWord(w)) { + words = (char **)realloc(words, sizeof (char *) * (wordCount + 1)); + assert(words != 0); + words[wordCount] = strdup(w); + assert(words[wordCount] != 0); + wordCount++; + } +} + +int colorCount; +struct _color { + char *colorName; + char *colorValue; +} *colors; + +int DefineColor(char *name, char *value) { + if (!name || !value) + return 0; + colors = (struct _color *)realloc(colors, sizeof (struct _color) * (colorCount + 1)); + assert(colors != 0); + colors[colorCount].colorName = strdup(name); + colors[colorCount].colorValue = strdup(value); + assert(colors != NULL); + assert(colors[colorCount].colorName != 0); + assert(colors[colorCount].colorValue != 0); + colorCount++; + return 1; +} + +char *DefinedColor(char *name) { + if (colors == 0 || colorCount == 0) + return 0; + for (int i = 0; i < colorCount; i++) + if (strcmp(name, colors[i].colorName) == 0) + return colors[i].colorValue; + return 0; +} + +char *GetColor(CurPos &cp, char *name) { + char *c; + static char color[4]; + + // add support for fore:back and remove it from fte itself + if ((c = strchr(name, ' ')) != NULL) { + } else if ((c = strchr(name, ':')) != NULL) { + char clr[4]; + *c++ = 0; + clr[0] = GetColor(cp, name)[0]; + clr[1] = ' '; + clr[2] = GetColor(cp, c)[2]; + clr[3] = 0; + + memcpy((void *)color, (void *)clr, sizeof(color)); + name = (char *)color; + } else { + char *p = DefinedColor(name); + if (!p) + Fail(cp, "Unknown symbolic color %s", name); + name = p; + } + if (!isxdigit(name[0]) && + name[1] != ' ' && + !isxdigit(name[2]) && + name[3] != 0) + { + Fail(cp, "malformed color specification: %s", name); + } + return name; +} + +int GetWord(CurPos &cp, char *w) { + char *p = w; + int len = 0; + + while (len < int(sizeof(Word)) && cp.c < cp.z && + ((*cp.c >= 'a' && *cp.c <= 'z') || + (*cp.c >= 'A' && *cp.c <= 'Z') || + (*cp.c >= '0' && *cp.c <= '9') || + (*cp.c == '_'))) + { + *p++ = *cp.c++; + len++; + } + if (len == sizeof(Word)) return -1; + *p = 0; + return 0; +} + + +int Parse(CurPos &cp) { + while (cp.c < cp.z) { + switch (*cp.c) { +#ifndef UNIX + case '\x1A': /* ^Z :-* */ return P_EOF; +#endif + case '#': + while (cp.c < cp.z && *cp.c != '\n') cp.c++; + break; + case '%': + cp.c++; + if (cp.c + 7 < cp.z && strncmp(cp.c, "define(", 7) == 0) { + Word w; + cp.c += 7; + + while (cp.c < cp.z && *cp.c != ')') { + GetWord(cp, w); + //printf("define '%s'\n", w); + DefineWord(w); + if (cp.c < cp.z && *cp.c != ',' && *cp.c != ')' ) + Fail(cp, "unexpected: %c", cp.c[0]); + if (cp.c < cp.z && *cp.c == ',') + cp.c++; + } + cp.c++; +/* } else if (cp.c + 6 && strcmp(cp.c, "undef(", 6) == 0) { + Word w; + cp.c += 6; + + while (cp.c < cp.z && *cp.c != ')') { + GetWord(cp, w); + UndefWord(w); + }*/ + } else if (cp.c + 3 < cp.z && strncmp(cp.c, "if(", 3) == 0) { + Word w; + int wasWord = 0; + cp.c += 3; + + while (cp.c < cp.z && *cp.c != ')') { + int neg = 0; + if (*cp.c == '!') { + cp.c++; + neg = 1; + } + GetWord(cp, w); + if (DefinedWord(w)) + wasWord = 1; + if (neg) + wasWord = wasWord ? 0 : 1; + /*if (wasWord) + printf("yes '%s'\n", w); + else + printf("not '%s'\n", w);*/ + + if (cp.c < cp.z && *cp.c != ',' && *cp.c != ')' ) + Fail(cp, "unexpected: %c", cp.c[0]); + if (cp.c < cp.z && *cp.c == ',') + cp.c++; + } + cp.c++; + if (!wasWord) { + int nest = 1; + while (cp.c < cp.z) { + if (*cp.c == '\n') { + cp.line++; + lntotal++; + } else if (*cp.c == '%') { + if (cp.c + 6 < cp.z && + strncmp(cp.c, "%endif", 6) == 0) + { + cp.c += 6; + if (--nest == 0) + break; + } + if (cp.c + 3 < cp.z && + strncmp(cp.c, "%if", 3) == 0) + { + cp.c += 3; + ++nest; + } + } else if (*cp.c == '#') { + // we really shouldn't process hashed % directives + while( cp.c < cp.z && *cp.c != '\n' ) cp.c++; + + // workaround to make line numbering correct + cp.line++; + lntotal++; + } + cp.c++; + } + } + } else if (cp.c + 5 < cp.z && strncmp(cp.c, "endif", 5) == 0) { + cp.c += 5; + } + if (cp.c < cp.z && *cp.c != '\n' && *cp.c != '\r') + Fail(cp, "syntax error %30.30s", cp.c); + break; + case '\n': + cp.line++; + lntotal++; + case ' ': + case '\t': + case '\r': + cp.c++; + break; + case '=': return P_ASSIGN; + case ';': return P_EOS; + case ',': return P_COMMA; + case ':': return P_COLON; + case '.': return P_DOT; + case '\'': + case '"': + case '`': + case '/': return P_STRING; + case '[': return P_KEYSPEC; + case '{': return P_OPENBRACE; + case '}': return P_CLOSEBRACE; + case '?': return P_QUEST; + case '$': return P_VARIABLE; + case '-': case '+': + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': return P_NUMBER; + default: + if ((*cp.c >= 'a' && *cp.c <= 'z') || + (*cp.c >= 'A' && *cp.c <= 'Z') || + (*cp.c == '_')) + return P_WORD; + else + return P_SYNTAX; + } + } + return P_EOF; +} + +void GetOp(CurPos &cp, int what) { + switch (what) { + case P_COMMA: + case P_OPENBRACE: + case P_CLOSEBRACE: + case P_ASSIGN: + case P_EOS: + case P_COLON: + case P_QUEST: + case P_VARIABLE: + case P_DOT: + cp.c++; + break; + } +} + +char *GetString(CurPos &cp) { + char c = *cp.c; + char *p = cp.c; + char *d = cp.c; + + if (c == '[') c = ']'; + + cp.c++; // skip '"` + while (cp.c < cp.z) { + if (*cp.c == '\\') { + if (c == '/') + *p++ = *cp.c; + cp.c++; + if (cp.c == cp.z) return 0; + if (c == '"') { + switch (*cp.c) { + case 'e': *cp.c = '\x1B'; break; + case 't': *cp.c = '\t'; break; + case 'r': *cp.c = '\r'; break; + case 'n': *cp.c = '\n'; break; + case 'b': *cp.c = '\b'; break; + case 'v': *cp.c = '\v'; break; + case 'a': *cp.c = '\a'; break; + } + } + } else if (*cp.c == c) { + cp.c++; + *p = 0; + return d; + } else if (*cp.c == '\n') return 0; + if (*cp.c == '\n') cp.line++; + if (*cp.c == '\r') { + cp.c++; + if (cp.c == cp.z) return 0; + } + *p++ = *cp.c++; + } + return 0; +} + +int GetNumber(CurPos &cp) { + int value = 0; + int neg = 0; + + if (cp.c < cp.z && *cp.c == '-' || *cp.c == '+') { + if (*cp.c == '-') neg = 1; + cp.c++; + } + while (cp.c < cp.z && (*cp.c >= '0' && *cp.c <= '9')) { + value = value * 10 + (*cp.c - '0'); + cp.c++; + } + return neg ? -value : value; +} + +int CmdNum(const char *Cmd) { + unsigned int i; + + for (i = 0; + i < sizeof(Command_Table) / sizeof(Command_Table[0]); + i++) + if (strcmp(Cmd, Command_Table[i].Name) == 0) + return Command_Table[i].CmdId; + for (i = 0; i < CMacros; i++) + if (Macros[i].Name && (strcmp(Cmd, Macros[i].Name)) == 0) + return i | CMD_EXT; + return 0; // Nop +} + +int NewCommand(const char *Name) { + if (Name == 0) + Name = ""; + Macros = (ExMacro *) realloc(Macros, sizeof(ExMacro) * (1 + CMacros)); + Macros[CMacros].Name = strdup(Name); + CMacros++; + return CMacros - 1; +} + +int ParseCommands(CurPos &cp, char *Name) { + //if (!Name) + // return 0; + Word cmd; + int p; + long Cmd = NewCommand(Name) | CMD_EXT; + + long cnt; + long ign = 0; + + PutNumber(cp, CF_INT, Cmd); + GetOp(cp, P_OPENBRACE); + cnt = 1; + while (1) { + p = Parse(cp); + if (p == P_CLOSEBRACE) break; + if (p == P_EOF) Fail(cp, "Unexpected EOF"); + + if (p == P_DOT) { + GetOp(cp, P_DOT); + PutNull(cp, CF_CONCAT); + } else if (p == P_NUMBER) { + long num = GetNumber(cp); + if (Parse(cp) != P_COLON) { + PutNumber(cp, CF_INT, num); + } else { + cnt = num; + GetOp(cp, P_COLON); + } + } else if (p == P_WORD) { + long Command; + + if (GetWord(cp, cmd) == -1) Fail(cp, "Syntax error"); + Command = CmdNum(cmd); + if (Command == 0) + Fail(cp, "Unrecognised command: %s", cmd); + PutNumber(cp, CF_COMMAND, Command); + PutNumber(cp, CF_INT, cnt); + PutNumber(cp, CF_INT, ign); + ign = 0; + cnt = 1; + } else if (p == P_STRING) { + char *s = GetString(cp); + PutString(cp, CF_STRING, s); + } else if (p == P_QUEST) { + ign = 1; + GetOp(cp, P_QUEST); + } else if (p == P_VARIABLE) { + GetOp(cp, P_VARIABLE); + if (Parse(cp) != P_WORD) Fail(cp, "Syntax error (variable name expected)"); + Word w; + if (GetWord(cp, w) != 0) Fail(cp, "Syntax error (bad variable name)"); + long var = Lookup(CfgVar, w); + if (var == -1) Fail(cp, "Unrecognised variable"); + PutNumber(cp, CF_VARIABLE, var); + } else if (p == P_EOS) { + GetOp(cp, P_EOS); + cnt = 1; + } else + Fail(cp, "Syntax error"); + } + GetOp(cp, P_CLOSEBRACE); + return 0; +} + +int ParseConfigFile(CurPos &cp) { + Word w = ""; + char *s = 0; + int p = 0; + + Word ObjName = "", UpMode = ""; + + while (1) { + p = Parse(cp); + + switch (p) { + case P_WORD: + if (GetWord(cp, w) != 0) Fail(cp, "Syntax error"); + switch (Lookup(CfgKW, w)) { + case K_SUB: + { + Word Name; + + if (Parse(cp) != P_WORD) Fail(cp, "Syntax error"); + if (GetWord(cp, Name) != 0) Fail(cp, "Syntax error"); + PutString(cp, CF_SUB, Name); + if (Parse(cp) != P_OPENBRACE) Fail(cp, "'{' expected"); + GetOp(cp, P_OPENBRACE); + if (ParseCommands(cp, strdup(Name ? Name : "")) == -1) + Fail(cp, "Parse failed"); + PutNull(cp, CF_END); + } + break; + case K_MENU: + + { + Word MenuName; + //int menu = -1, item = -1; + + if (Parse(cp) != P_WORD) Fail(cp, "Syntax error");; + if (GetWord(cp, MenuName) != 0) Fail(cp, "Syntax error");; + if (Parse(cp) != P_OPENBRACE) Fail(cp, "'{' expected"); + GetOp(cp, P_OPENBRACE); + + PutString(cp, CF_MENU, MenuName); + + while (1) { + p = Parse(cp); + if (p == P_CLOSEBRACE) break; + if (p == P_EOF) Fail(cp, "Unexpected EOF"); + if (p != P_WORD) Fail(cp, "Syntax error"); + + if (GetWord(cp, w) != 0) Fail(cp, "Parse failed"); + switch (Lookup(CfgKW, w)) { + case K_ITEM: // menu::item + switch (Parse(cp)) { + case P_EOS: + PutNull(cp, CF_ITEM); + break; + case P_STRING: + s = GetString(cp); + PutString(cp, CF_ITEM, s); + break; + default: + Fail(cp, "Syntax error");; + } + if (Parse(cp) == P_EOS) { + GetOp(cp, P_EOS); + break; + } + if (Parse(cp) != P_OPENBRACE) + Fail(cp, "'{' expected"); + + PutNull(cp, CF_MENUSUB); + if (ParseCommands(cp, 0) == -1) + Fail(cp, "Parse failed"); + PutNull(cp, CF_END); + break; + case K_SUBMENU: // menu::submenu + if (Parse(cp) != P_STRING) + Fail(cp, "String expected"); + s = GetString(cp); + if (Parse(cp) != P_COMMA) + Fail(cp, "',' expected"); + GetOp(cp, P_COMMA); + if (Parse(cp) != P_WORD) + Fail(cp, "Syntax error"); + if (GetWord(cp, w) == -1) + Fail(cp, "Parse failed"); + + PutString(cp, CF_SUBMENU, s); + PutString(cp, CF_STRING, w); + if (Parse(cp) != P_EOS) + Fail(cp, "';' expected"); + GetOp(cp, P_EOS); + break; + + case K_SUBMENUCOND: // menu::submenu + if (Parse(cp) != P_STRING) + Fail(cp, "String expected"); + s = GetString(cp); + if (Parse(cp) != P_COMMA) + Fail(cp, "',' expected"); + GetOp(cp, P_COMMA); + if (Parse(cp) != P_WORD) + Fail(cp, "Syntax error"); + if (GetWord(cp, w) == -1) + Fail(cp, "Parse failed"); + + PutString(cp, CF_SUBMENUCOND, s); + PutString(cp, CF_STRING, w); + if (Parse(cp) != P_EOS) + Fail(cp, "';' expected"); + GetOp(cp, P_EOS); + break; + default: // menu:: + Fail(cp, "Syntax error"); + } + } + GetOp(cp, P_CLOSEBRACE); + PutNull(cp, CF_END); + } + break; + case K_EVENTMAP: + { + if (Parse(cp) != P_WORD) Fail(cp, "Syntax error"); + if (GetWord(cp, ObjName) != 0) Fail(cp, "Parse failed"); + PutString(cp, CF_EVENTMAP, ObjName); + + UpMode[0] = 0; + if (Parse(cp) == P_COLON) { + GetOp(cp, P_COLON); + if (Parse(cp) != P_WORD) Fail(cp, "Syntax error"); + if (GetWord(cp, UpMode) != 0) Fail(cp, "Parse failed"); + } + PutString(cp, CF_PARENT, UpMode); + if (Parse(cp) != P_OPENBRACE) Fail(cp, "'{' expected"); + GetOp(cp, P_OPENBRACE); + + while (1) { + p = Parse(cp); + if (p == P_CLOSEBRACE) break; + if (p == P_EOF) Fail(cp, "Unexpected EOF"); + if (p != P_WORD) Fail(cp, "Syntax error"); + + if (GetWord(cp, w) != 0) Fail(cp, "Parse failed"); + switch (Lookup(CfgKW, w)) { + case K_KEY: // mode::key + if (Parse(cp) != P_KEYSPEC) Fail(cp, "'[' expected"); + s = GetString(cp); + PutString(cp, CF_KEY, s); + if (Parse(cp) != P_OPENBRACE) Fail(cp, "'{' expected"); + PutNull(cp, CF_KEYSUB); + if (ParseCommands(cp, 0) == -1) Fail(cp, "Parse failed"); + PutNull(cp, CF_END); + break; + + case K_ABBREV: + if (Parse(cp) != P_STRING) Fail(cp, "String expected"); + s = GetString(cp); + PutString(cp, CF_ABBREV, s); + switch (Parse(cp)) { + case P_OPENBRACE: + PutNull(cp, CF_KEYSUB); + if (ParseCommands(cp, 0) == -1) Fail(cp, "Parse failed"); + PutNull(cp, CF_END); + break; + case P_STRING: + s = GetString(cp); + PutString(cp, CF_STRING, s); + if (Parse(cp) != P_EOS) Fail(cp, "';' expected"); + GetOp(cp, P_EOS); + break; + default: + Fail(cp, "Syntax error"); + } + break; + + default: // mode:: + if (Parse(cp) != P_ASSIGN) Fail(cp, "'=' expected"); + GetOp(cp, P_ASSIGN); + + switch (Parse(cp)) { + /* case P_NUMBER: + { + long var; + long num; + + num = GetNumber(cp); + var = LookupEventNumber(w); + if (var == -1) return -1; + PutObj(cp, CF_SETVAR, sizeof(long), &var); + PutObj(cp, CF_INT, sizeof(long), &num); + } + break;*/ + case P_STRING: + { + long var; + + s = GetString(cp); + if (s == 0) Fail(cp, "String expected"); + var = Lookup(event_string, w); + if (var == -1) Fail(cp, "Lookup of '%s' failed", w); + PutNumber(cp, CF_SETVAR, var); + PutString(cp, CF_STRING, s); + } + break; + default: + return -1; + } + if (Parse(cp) != P_EOS) return -1; + GetOp(cp, P_EOS); + break; + } + } + GetOp(cp, P_CLOSEBRACE); + PutNull(cp, CF_END); + } + break; + + case K_COLORIZE: + { + long LastState = -1; + + if (Parse(cp) != P_WORD) Fail(cp, "Syntax error"); + if (GetWord(cp, ObjName) != 0) Fail(cp, "Parse failed"); + PutString(cp, CF_COLORIZE, ObjName); + + UpMode[0] = 0; + if (Parse(cp) == P_COLON) { + GetOp(cp, P_COLON); + if (Parse(cp) != P_WORD) Fail(cp, "Syntax error"); + if (GetWord(cp, UpMode) != 0) Fail(cp, "Parse failed"); + } + PutString(cp, CF_PARENT, UpMode); + if (Parse(cp) != P_OPENBRACE) Fail(cp, "'{' expected"); + GetOp(cp, P_OPENBRACE); + + while (1) { + p = Parse(cp); + if (p == P_CLOSEBRACE) break; + if (p == P_EOF) Fail(cp, "Unexpected EOF"); + if (p != P_WORD) Fail(cp, "Syntax error"); + + if (GetWord(cp, w) != 0) Fail(cp, "Parse failed"); + switch (Lookup(CfgKW, w)) { + case K_COLOR: // mode::color + if (Parse(cp) != P_OPENBRACE) Fail(cp, "'{' expected"); + GetOp(cp, P_OPENBRACE); + PutNull(cp, CF_COLOR); + + while (1) { + char *sname, *svalue; + long cidx; + + if (Parse(cp) == P_CLOSEBRACE) break; + if (Parse(cp) != P_OPENBRACE) Fail(cp, "'{' expected"); + GetOp(cp, P_OPENBRACE); + if (Parse(cp) != P_STRING) Fail(cp, "String expected"); + sname = GetString(cp); + if ((cidx = Lookup(hilit_colors, sname)) == -1) + Fail(cp, "Lookup of '%s' failed", sname); + PutNumber(cp, CF_INT, cidx); + if (Parse(cp) != P_COMMA) + Fail(cp, "',' expected"); + GetOp(cp, P_COMMA); + if (Parse(cp) != P_STRING) Fail(cp, "String expected"); + svalue = GetString(cp); + svalue = GetColor(cp, svalue); + PutString(cp, CF_STRING, svalue); + if (Parse(cp) != P_CLOSEBRACE) Fail(cp, "'}' expected"); + GetOp(cp, P_CLOSEBRACE); + if (Parse(cp) != P_COMMA) + break; + else + GetOp(cp, P_COMMA); + } + if (Parse(cp) != P_CLOSEBRACE) Fail(cp, "'}' expected"); + GetOp(cp, P_CLOSEBRACE); + if (Parse(cp) != P_EOS) Fail(cp, "';' expected"); + GetOp(cp, P_EOS); + PutNull(cp, CF_END); + break; + + case K_KEYWORD: // mode::keyword + { + char *colorstr, *kname; + //int color; + + if (Parse(cp) != P_STRING) Fail(cp, "String expected"); + colorstr = GetString(cp); + colorstr = GetColor(cp, colorstr); + if (Parse(cp) != P_OPENBRACE) Fail(cp, "'{' expected"); + GetOp(cp, P_OPENBRACE); + + PutString(cp, CF_KEYWORD, colorstr); + + while (1) { + if (Parse(cp) == P_CLOSEBRACE) break; + if (Parse(cp) != P_STRING) Fail(cp, "String expected"); + kname = GetString(cp); + PutString(cp, CF_STRING, kname); + + if (Parse(cp) != P_COMMA) + break; + else + GetOp(cp, P_COMMA); + } + } + if (Parse(cp) != P_CLOSEBRACE) Fail(cp, "'}' expected"); + GetOp(cp, P_CLOSEBRACE); + if (Parse(cp) != P_EOS) Fail(cp, "';' expected"); + GetOp(cp, P_EOS); + PutNull(cp, CF_END); + break; + + case K_HSTATE: + { + long stateno; + char *cname; + long cidx; + + if (Parse(cp) != P_NUMBER) Fail(cp, "state index expected"); + stateno = GetNumber(cp); + if (stateno != LastState + 1) Fail(cp, "invalid state index"); + + if (Parse(cp) != P_OPENBRACE) Fail(cp, "'{' expected"); + GetOp(cp, P_OPENBRACE); + PutNumber(cp, CF_HSTATE, stateno); + + if (Parse(cp) != P_STRING) Fail(cp, "String expected"); + cname = GetString(cp); + if ((cidx = Lookup(hilit_colors, cname)) == -1) + Fail(cp, "Lookup of '%s' failed", cname); + PutNumber(cp, CF_INT, cidx); + if (Parse(cp) != P_CLOSEBRACE) Fail(cp, "'}' expected"); + GetOp(cp, P_CLOSEBRACE); + LastState = stateno; + } + break; + + case K_HTRANS: + { + long next_state; + char *opts, *match; + long match_opts; + char *cname; + long cidx; + + if (Parse(cp) != P_OPENBRACE) Fail(cp, "'{' expected"); + GetOp(cp, P_OPENBRACE); + + if (Parse(cp) != P_NUMBER) Fail(cp, "next_state index expected"); + next_state = GetNumber(cp); + if (Parse(cp) != P_COMMA) Fail(cp, "',' expected"); + GetOp(cp, P_COMMA); + if (Parse(cp) != P_STRING) Fail(cp, "match options expected"); + opts = GetString(cp); + if (Parse(cp) != P_COMMA) Fail(cp, "',' expected"); + GetOp(cp, P_COMMA); + if (Parse(cp) != P_STRING) Fail(cp, "match string expected"); + match = GetString(cp); + PutNumber(cp, CF_HTRANS, next_state); + match_opts = 0; + if (strchr(opts, '^')) match_opts |= MATCH_MUST_BOL; + if (strchr(opts, '$')) match_opts |= MATCH_MUST_EOL; + //if (strchr(opts, 'b')) match_opts |= MATCH_MUST_BOLW; + //if (strchr(opts, 'e')) match_opts |= MATCH_MUST_EOLW; + if (strchr(opts, 'i')) match_opts |= MATCH_NO_CASE; + if (strchr(opts, 's')) match_opts |= MATCH_SET; + if (strchr(opts, 'S')) match_opts |= MATCH_NOTSET; + if (strchr(opts, '-')) match_opts |= MATCH_NOGRAB; + if (strchr(opts, '<')) match_opts |= MATCH_TAGASNEXT; + if (strchr(opts, '>')) match_opts &= ~MATCH_TAGASNEXT; + //if (strchr(opts, '!')) match_opts |= MATCH_NEGATE; + if (strchr(opts, 'q')) match_opts |= MATCH_QUOTECH; + if (strchr(opts, 'Q')) match_opts |= MATCH_QUOTEEOL; + + if (Parse(cp) != P_COMMA) Fail(cp, "',' expected"); + GetOp(cp, P_COMMA); + if (Parse(cp) != P_STRING) Fail(cp, "String expected"); + cname = GetString(cp); + if ((cidx = Lookup(hilit_colors, cname)) == -1) + Fail(cp, "Lookup of '%s' failed", cname); + + PutNumber(cp, CF_INT, match_opts); + PutNumber(cp, CF_INT, cidx); + PutString(cp, CF_STRING, match); + + if (Parse(cp) != P_CLOSEBRACE) Fail(cp, "'}' expected"); + GetOp(cp, P_CLOSEBRACE); + } + break; + + case K_HWTYPE: + if (Parse(cp) != P_OPENBRACE) Fail(cp, "'{' expected"); + GetOp(cp, P_OPENBRACE); + + { + long options = 0; + long nextKwdMatchedState; + long nextKwdNotMatchedState; + long nextKwdNoCharState; + char *opts; + char *wordChars; + + + if (Parse(cp) != P_NUMBER) Fail(cp, "next_state index expected"); + nextKwdMatchedState = GetNumber(cp); + + if (Parse(cp) != P_COMMA) Fail(cp, "',' expected"); + GetOp(cp, P_COMMA); + + if (Parse(cp) != P_NUMBER) Fail(cp, "next_state index expected"); + nextKwdNotMatchedState = GetNumber(cp); + + if (Parse(cp) != P_COMMA) Fail(cp, "',' expected"); + GetOp(cp, P_COMMA); + + if (Parse(cp) != P_NUMBER) Fail(cp, "next_state index expected"); + nextKwdNoCharState = GetNumber(cp); + + if (Parse(cp) != P_COMMA) Fail(cp, "',' expected"); + GetOp(cp, P_COMMA); + + if (Parse(cp) != P_STRING) Fail(cp, "String expected"); + opts = GetString(cp); + if (strchr(opts, 'i')) options |= STATE_NOCASE; + if (strchr(opts, '<')) options |= STATE_TAGASNEXT; + if (strchr(opts, '>')) options &= ~STATE_TAGASNEXT; + if (strchr(opts, '-')) options |= STATE_NOGRAB; + + if (Parse(cp) != P_COMMA) Fail(cp, "',' expected"); + GetOp(cp, P_COMMA); + + if (Parse(cp) != P_STRING) Fail(cp, "String expected"); + wordChars = GetString(cp); + + PutNull(cp, CF_HWTYPE); + PutNumber(cp, CF_INT, nextKwdMatchedState); + PutNumber(cp, CF_INT, nextKwdNotMatchedState); + PutNumber(cp, CF_INT, nextKwdNoCharState); + PutNumber(cp, CF_INT, options); + PutString(cp, CF_STRING, wordChars); + } + if (Parse(cp) != P_CLOSEBRACE) Fail(cp, "'}' expected"); + GetOp(cp, P_CLOSEBRACE); + break; + + case K_HWORDS: + { + char *colorstr, *kname; + //int color; + + if (Parse(cp) != P_STRING) Fail(cp, "String expected"); + colorstr = GetString(cp); + colorstr = GetColor(cp, colorstr); + + if (Parse(cp) != P_OPENBRACE) Fail(cp, "'{' expected"); + GetOp(cp, P_OPENBRACE); + + PutString(cp, CF_HWORDS, colorstr); + + while (1) { + if (Parse(cp) == P_CLOSEBRACE) break; + if (Parse(cp) != P_STRING) Fail(cp, "String expected"); + kname = GetString(cp); + PutString(cp, CF_STRING, kname); + + if (Parse(cp) != P_COMMA) + break; + else + GetOp(cp, P_COMMA); + } + } + if (Parse(cp) != P_CLOSEBRACE) Fail(cp, "'}' expected"); + GetOp(cp, P_CLOSEBRACE); + + PutNull(cp, CF_END); + break; + + default: + if (Parse(cp) != P_ASSIGN) Fail(cp, "'=' expected"); + GetOp(cp, P_ASSIGN); + switch (Parse(cp)) { + /*case P_NUMBER: + { + long var; + long num; + + num = GetNumber(cp); + var = LookupColorizeNumber(w); + if (var == -1) return -1; + PutObj(cp, CF_SETVAR, sizeof(long), &var); + PutObj(cp, CF_INT, sizeof(long), &num); + } + break;*/ + case P_STRING: + { + long var; + + s = GetString(cp); + if (s == 0) Fail(cp, "Parse failed"); + var = Lookup(colorize_string, w); + if (var == -1) + Fail(cp, "Lookup of '%s' failed", w); + PutNumber(cp, CF_SETVAR, var); + PutString(cp, CF_STRING, s); + } + break; + default: + return -1; + } + if (Parse(cp) != P_EOS) Fail(cp, "';' expected"); + GetOp(cp, P_EOS); + break; + } + } + GetOp(cp, P_CLOSEBRACE); + PutNull(cp, CF_END); + } + break; + + case K_MODE: // mode:: + { + if (Parse(cp) != P_WORD) Fail(cp, "Syntax error"); + if (GetWord(cp, ObjName) != 0) Fail(cp, "Parse failed"); + PutString(cp, CF_MODE, ObjName); + + UpMode[0] = 0; + if (Parse(cp) == P_COLON) { + GetOp(cp, P_COLON); + if (Parse(cp) != P_WORD) Fail(cp, "Syntax error"); + if (GetWord(cp, UpMode) != 0) Fail(cp, "Parse failed"); + } + PutString(cp, CF_PARENT, UpMode); + if (Parse(cp) != P_OPENBRACE) Fail(cp, "'{' expected"); + GetOp(cp, P_OPENBRACE); + + while (1) { + p = Parse(cp); + if (p == P_CLOSEBRACE) break; + if (p == P_EOF) Fail(cp, "Unexpected EOF"); + if (p != P_WORD) Fail(cp, "Syntax error"); + + if (GetWord(cp, w) != 0) Fail(cp, "Parse failed"); + //switch (Lookup(CfgKW, w)) { + //default: // mode:: + if (Parse(cp) != P_ASSIGN) Fail(cp, "'=' expected"); + GetOp(cp, P_ASSIGN); + switch (Parse(cp)) { + case P_NUMBER: + { + long var; + long num; + + num = GetNumber(cp); + var = Lookup(mode_num, w); + if (var == -1) + Fail(cp, "Lookup of '%s' failed", w); + PutNumber(cp, CF_SETVAR, var); + PutNumber(cp, CF_INT, num); + } + break; + case P_STRING: + { + long var; + + s = GetString(cp); + if (s == 0) Fail(cp, "Parse failed"); + var = Lookup(mode_string, w); + if (var == -1) + Fail(cp, "Lookup of '%s' filed", w); + PutNumber(cp, CF_SETVAR, var); + PutString(cp, CF_STRING, s); + } + break; + default: + return -1; + } + if (Parse(cp) != P_EOS) Fail(cp, "';' expected"); + GetOp(cp, P_EOS); + // break; + //} + } + GetOp(cp, P_CLOSEBRACE); + PutNull(cp, CF_END); + } + break; + case K_OBJECT: + { + if (Parse(cp) != P_WORD) Fail(cp, "Syntax error"); + if (GetWord(cp, ObjName) != 0) Fail(cp, "Parse failed"); + if (Parse(cp) != P_OPENBRACE) Fail(cp, "'{' expected"); + GetOp(cp, P_OPENBRACE); + + PutString(cp, CF_OBJECT, ObjName); + + while (1) { + p = Parse(cp); + if (p == P_CLOSEBRACE) break; + if (p == P_EOF) Fail(cp, "Unexpected EOF"); + if (p != P_WORD) Fail(cp, "Syntax error"); + + if (GetWord(cp, w) != 0) Fail(cp, "Parse failed"); + switch (Lookup(CfgKW, w)) { + case K_COLOR: // mode::color + if (Parse(cp) != P_OPENBRACE) Fail(cp, "'{' expected"); + GetOp(cp, P_OPENBRACE); + PutNull(cp, CF_COLOR); + + while (1) { + char *sname, *svalue; + + if (Parse(cp) == P_CLOSEBRACE) break; + if (Parse(cp) != P_OPENBRACE) Fail(cp, "'{' expected"); + GetOp(cp, P_OPENBRACE); + if (Parse(cp) != P_STRING) Fail(cp, "String expected"); + sname = GetString(cp); + PutString(cp, CF_STRING, sname); + if (Parse(cp) != P_COMMA) Fail(cp, "',' expected"); + GetOp(cp, P_COMMA); + if (Parse(cp) != P_STRING) Fail(cp, "String expected"); + svalue = GetString(cp); + svalue = GetColor(cp, svalue); + PutString(cp, CF_STRING, svalue); + if (Parse(cp) != P_CLOSEBRACE) Fail(cp, "'}' expected"); + GetOp(cp, P_CLOSEBRACE); + if (Parse(cp) != P_COMMA) + break; + else + GetOp(cp, P_COMMA); + } + if (Parse(cp) != P_CLOSEBRACE) Fail(cp, "'}' expected"); + GetOp(cp, P_CLOSEBRACE); + if (Parse(cp) != P_EOS) Fail(cp, "';' expected"); + GetOp(cp, P_EOS); + PutNull(cp, CF_END); + break; + + case K_COMPILERX: + { + long file, line, msg; + char *regexp; + + if (Parse(cp) != P_ASSIGN) Fail(cp, "'=' expected"); + GetOp(cp, P_ASSIGN); + if (Parse(cp) != P_OPENBRACE) Fail(cp, "'{' expected"); + GetOp(cp, P_OPENBRACE); + if (Parse(cp) != P_NUMBER) Fail(cp, "Number expected"); + file = GetNumber(cp); + if (Parse(cp) != P_COMMA) Fail(cp, "',' expected"); + GetOp(cp, P_COMMA); + if (Parse(cp) != P_NUMBER) Fail(cp, "Number expected"); + line = GetNumber(cp); + if (Parse(cp) != P_COMMA) Fail(cp, "',' expected"); + GetOp(cp, P_COMMA); + if (Parse(cp) != P_NUMBER) Fail(cp, "Number expected"); + msg = GetNumber(cp); + if (Parse(cp) != P_COMMA) Fail(cp, "',' expected"); + GetOp(cp, P_COMMA); + if (Parse(cp) != P_STRING) Fail(cp, "String expected"); + regexp = GetString(cp); + if (Parse(cp) != P_CLOSEBRACE) Fail(cp, "'}' expected"); + GetOp(cp, P_CLOSEBRACE); + PutNull(cp, CF_COMPRX); + PutNumber(cp, CF_INT, file); + PutNumber(cp, CF_INT, line); + PutNumber(cp, CF_INT, msg); + PutString(cp, CF_REGEXP, regexp); + if (Parse(cp) != P_EOS) Fail(cp, "';' expected"); + GetOp(cp, P_EOS); + } + break; + default: // mode:: + if (Parse(cp) != P_ASSIGN) Fail(cp, "'=' expected"); + GetOp(cp, P_ASSIGN); + + switch (Parse(cp)) { + case P_NUMBER: + { + long var; + long num; + + num = GetNumber(cp); + var = Lookup(global_num, w); + if (var == -1) + Fail(cp, "Lookup of '%s' failed", w); + PutNumber(cp, CF_SETVAR, var); + PutNumber(cp, CF_INT, num); + } + break; + case P_STRING: + { + long var; + + s = GetString(cp); + if (s == 0) Fail(cp, "Parse failed"); + var = Lookup(global_string, w); + if (var == -1) Fail(cp, "Lookup of '%s' failed"); + PutNumber(cp, CF_SETVAR, var); + PutString(cp, CF_STRING, s); + } + break; + default: + Fail(cp, "Syntax error"); + } + if (Parse(cp) != P_EOS) Fail(cp, "';' expected"); + GetOp(cp, P_EOS); + break; + } + } + GetOp(cp, P_CLOSEBRACE); + PutNull(cp, CF_END); + } + break; + + case K_COLPALETTE: + { + if (Parse(cp) != P_OPENBRACE) Fail(cp, "'{' expected"); + GetOp(cp, P_OPENBRACE); + + while (1) { + char *sname, *svalue; + + if (Parse(cp) == P_CLOSEBRACE) break; + if (Parse(cp) != P_OPENBRACE) Fail(cp, "'{' expected"); + GetOp(cp, P_OPENBRACE); + if (Parse(cp) != P_STRING) Fail(cp, "String expected"); + sname = GetString(cp); + if (Parse(cp) != P_COMMA) Fail(cp, "',' expected"); + GetOp(cp, P_COMMA); + if (Parse(cp) != P_STRING) Fail(cp, "String expected"); + svalue = GetString(cp); + svalue = GetColor(cp, svalue); + assert(DefineColor(sname, svalue) == 1); + if (Parse(cp) != P_CLOSEBRACE) Fail(cp, "'}' expected"); + GetOp(cp, P_CLOSEBRACE); + if (Parse(cp) != P_COMMA) + break; + else + GetOp(cp, P_COMMA); + } + if (Parse(cp) != P_CLOSEBRACE) Fail(cp, "'}' expected"); + GetOp(cp, P_CLOSEBRACE); + } + break; + case K_INCLUDE: + { + char *fn; + + if (Parse(cp) != P_STRING) Fail(cp, "String expected"); + fn = GetString(cp); + + if (LoadFile(cp.name, fn) != 0) Fail(cp, "Include of file '%s' failed", fn); + if (Parse(cp) != P_EOS) Fail(cp, "';' expected"); + GetOp(cp, P_EOS); + } + break; + default: + Fail(cp, "Syntax error"); + } + break; + case P_EOF: return 0; + default: Fail(cp, "Syntax error"); + } + } +} + +int LoadFile(const char *WhereName, const char *CfgName, int Level) { + int fd, rc; + char *buffer = 0; + struct stat statbuf; + CurPos cp; + char last[MAXPATH]; + char Cfg[MAXPATH]; + + //fprintf(stderr, "Loading file %s %s\n", WhereName, CfgName); + + JustDirectory(WhereName, last); + + if (IsFullPath(CfgName)) { + strcpy(Cfg, CfgName); + } else { + // here we will try relative to a number of places. + // 1. User's .fte directory. + // 2. System's "local config" directory. + // 3. Initial file's directory. + // 4. Current directory. + // This means that a user's directory will always win out, + // allowing a given user to always be able to override everything, + // followed by a system standard to override anything. + + // #'s 1 and 2 are unix-only. +#ifdef UNIX + // 1. User's .fte directory. + char tmp[MAXPATH]; + sprintf(tmp, "~/.fte/%s", CfgName); + ExpandPath(tmp, Cfg); + //fprintf(stderr, "Looking for %s\n", Cfg); + if (!FileExists(Cfg)) + { + // Okay, now try "local config". + sprintf(tmp, "%slocalconfig/%s", StartDir, CfgName); + ExpandPath(tmp, Cfg); + //fprintf(stderr, "Looking for %s\n", Cfg); + if (!FileExists(Cfg)) + { + sprintf(tmp, "%sconfig/%s", StartDir, CfgName); + ExpandPath(tmp, Cfg); + //fprintf(stderr, "Looking for %s\n", Cfg); + if (!FileExists(Cfg)) + { + sprintf(tmp, "./%s", CfgName); + ExpandPath(tmp, Cfg); + //fprintf(stderr, "Looking for %s\n", Cfg); + if (!FileExists(Cfg)) + { + fprintf(stderr, "Cannot find '%s' in:\n" + "\t~/.fte,\n""\t%slocalconfig,\n" + "\t%sconfig, or\n" + "\t.", + CfgName, StartDir, StartDir); + } + } + } + } +#else // UNIX + SlashDir(last); + strcat(last, CfgName); + ExpandPath(last, Cfg); +#endif // UNIX + } + // puts(Cfg); + + //fprintf(stderr, "Loading file %s\n", Cfg); + if ((fd = open(Cfg, O_RDONLY | O_BINARY)) == -1) { + fprintf(stderr, "Cannot open '%s', errno=%d\n", Cfg, errno); + return -1; + } + if (fstat(fd, &statbuf) != 0) { + close(fd); + fprintf(stderr, "Cannot stat '%s', errno=%d\n", Cfg, errno); + return -1; + } + buffer = (char *) malloc(statbuf.st_size); + if (buffer == 0) { + close(fd); + return -1; + } + if (read(fd, buffer, statbuf.st_size) != statbuf.st_size) { + close(fd); + free(buffer); + return -1; + } + close(fd); + + cp.sz = statbuf.st_size; + cp.a = cp.c = buffer; + cp.z = cp.a + cp.sz; + cp.line = 1; + cp.name = Cfg; + + rc = ParseConfigFile(cp); + // puts("End Loading file"); + if (Level == 0) + PutNull(cp, CF_EOF); + + if (rc == -1) { + Fail(cp, "Parse failed"); + } + free(buffer); + return rc; +} diff --git a/src/cfte.def b/src/cfte.def new file mode 100644 index 0000000..6719c3d --- /dev/null +++ b/src/cfte.def @@ -0,0 +1,3 @@ +NAME cfte WINDOWCOMPAT +DESCRIPTION 'FTE Configuration Compiler' +STACKSIZE 49152 diff --git a/src/clip.h b/src/clip.h new file mode 100644 index 0000000..8da28d4 --- /dev/null +++ b/src/clip.h @@ -0,0 +1,28 @@ +/* clip.h + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#ifndef __CLIPLIB_H +#define __CLIPLIB_H + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + unsigned long fLen; + char *fChar; +} ClipData; + +int GetClipText(ClipData *cd); +int PutClipText(ClipData *cd); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/clip_gpm.cpp b/src/clip_gpm.cpp new file mode 100644 index 0000000..caf3057 --- /dev/null +++ b/src/clip_gpm.cpp @@ -0,0 +1,18 @@ +/* clip_gpm.cpp + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#include "fte.h" + +int GetPMClip() { + return 0; +} + +int PutPMClip() { + return 0; +} diff --git a/src/clip_no.cpp b/src/clip_no.cpp new file mode 100644 index 0000000..c2fae06 --- /dev/null +++ b/src/clip_no.cpp @@ -0,0 +1,18 @@ +/* clip_no.cpp + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#include "fte.h" + +int GetPMClip() { + return 0; +} + +int PutPMClip() { + return 0; +} diff --git a/src/clip_os2.cpp b/src/clip_os2.cpp new file mode 100644 index 0000000..24294a3 --- /dev/null +++ b/src/clip_os2.cpp @@ -0,0 +1,71 @@ +/* clip_os2.cpp + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#include "fte.h" +#include "clip.h" + +int GetPMClip() { + ClipData cd; + unsigned int i,j, l, dx; + EPoint P; + + if (GetClipText(&cd) == 0) { + SSBuffer->Clear(); + j = 0; + l = 0; + + for (i = 0; i < cd.fLen; i++) { + if (cd.fChar[i] == 0x0A) { + SSBuffer->AssertLine(l); + P.Col = 0; P.Row = l++; + dx = 0; + if ((i > 0) && (cd.fChar[i-1] == 0x0D)) dx++; + SSBuffer->InsertLine(P, i - j - dx, cd.fChar + j); + j = i + 1; + } + } + if (j < cd.fLen) { // remainder + i = cd.fLen; + SSBuffer->AssertLine(l); + P.Col = 0; P.Row = l++; + dx = 0; + if ((i > 0) && (cd.fChar[i-1] == 0x0D)) dx++; + SSBuffer->InsText(P.Row, P.Col, i - j - dx, cd.fChar + j); + j = i + 1; + } + } + return 0; +} + +int PutPMClip() { + char *p = 0; + int l = 0; + PELine L; + int Len; + ClipData cd; + int rc; + + for (int i = 0; i < SSBuffer->RCount; i++) { + L = SSBuffer->RLine(i); + p = (char *)realloc(p, l + (Len = L->Count) + 2); + memcpy(p + l, L->Chars, L->Count); + l += Len; + if (i < SSBuffer->RCount - 1) { + p[l++] = 13; + p[l++] = 10; + } + } + p = (char *)realloc(p, l + 1); + p[l++] = 0; + cd.fChar = p; + cd.fLen = l; + rc = (PutClipText(&cd) == 0); + free(p); + return rc?1:0; +} diff --git a/src/clip_pm.cpp b/src/clip_pm.cpp new file mode 100644 index 0000000..b063039 --- /dev/null +++ b/src/clip_pm.cpp @@ -0,0 +1,57 @@ +/* clip_pm.cpp + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#include "fte.h" +#include "clip.h" + +#define INCL_WIN +#include +#include +#include + +extern HAB hab; + +int GetClipText(ClipData *cd) { + int rc; + char *text; + + cd->fLen = 0; + cd->fChar = 0; + if ((WinOpenClipbrd(hab) == TRUE) && + ((text = (char *) WinQueryClipbrdData(hab, CF_TEXT)) != 0)) + { + cd->fLen = strlen(text); + cd->fChar = strdup(text); + } + WinCloseClipbrd(hab); + return 0; +} + +int PutClipText(ClipData *cd) { + ULONG len; + void *text; + + if (WinOpenClipbrd(hab) == TRUE) { + WinEmptyClipbrd(hab); + len = cd->fLen; + + if (len) { + DosAllocSharedMem((void **)&text, + 0, + len + 1, + PAG_READ | PAG_WRITE | PAG_COMMIT | OBJ_GIVEABLE); + strncpy((char *)text, cd->fChar, len + 1); + if (!WinSetClipbrdData(hab, (ULONG) text, CF_TEXT, CFI_POINTER)) + DosBeep(100, 1500); + + } + WinCloseClipbrd(hab); + } + return 0; +} diff --git a/src/clip_pmv.cpp b/src/clip_pmv.cpp new file mode 100644 index 0000000..5e323e1 --- /dev/null +++ b/src/clip_pmv.cpp @@ -0,0 +1,439 @@ +/* clip_pm.cpp + * + * Copyright (c) 1994-1998, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#include "fte.h" +#include "clip.h" + +#define INCL_WIN +#define INCL_DOS +#define INCL_ORDINALS +#include +#include +#include + +/* + * Pointers to PM functions + * Instead of calling PM directly, we are obtaining these pointers + * on first access to clipboard. + * All these prototypes are copied from OS2.H + * Note: all prototypes are 32-bit version only + */ + +#define ORD_WIN32ADDATOM 700 +#define ORD_WIN32ALARM 701 +#define ORD_WIN32BEGINENUMWINDOWS 702 +#define ORD_WIN32BEGINPAINT 703 +#define ORD_WIN32CALCFRAMERECT 704 +#define ORD_WIN32CANCELSHUTDOWN 705 +#define ORD_WIN32CLOSECLIPBRD 707 +#define ORD_WIN32COMPARESTRINGS 708 +#define ORD_WIN32COPYACCELTABLE 709 +#define ORD_WIN32COPYRECT 710 +#define ORD_WIN32CPTRANSLATECHAR 711 +#define ORD_WIN32CPTRANSLATESTRING 712 +#define ORD_WIN32CREATEACCELTABLE 713 +#define ORD_WIN32CREATEATOMTABLE 714 +#define ORD_WIN32CREATECURSOR 715 +#define ORD_WIN32CREATEMSGQUEUE 716 +#define ORD_WIN32CREATEPOINTER 717 +#define ORD_WIN32DDEINITIATE 718 +#define ORD_WIN32DDEPOSTMSG 719 +#define ORD_WIN32DDERESPOND 720 +#define ORD_WIN32DELETEATOM 721 +#define ORD_WIN32DELETELIBRARY 722 +#define ORD_WIN32DESTROYACCELTABLE 723 +#define ORD_WIN32DESTROYATOMTABLE 724 +#define ORD_WIN32DESTROYCURSOR 725 +#define ORD_WIN32DESTROYMSGQUEUE 726 +#define ORD_WIN32DESTROYPOINTER 727 +#define ORD_WIN32DESTROYWINDOW 728 +#define ORD_WIN32DISMISSDLG 729 +#define ORD_WIN32DRAWBITMAP 730 +#define ORD_WIN32DRAWBORDER 731 +#define ORD_WIN32DRAWPOINTER 732 +#define ORD_WIN32EMPTYCLIPBRD 733 +#define ORD_WIN32ENABLEPHYSINPUT 734 +#define ORD_WIN32ENABLEWINDOW 735 +#define ORD_WIN32ENABLEWINDOWUPDATE 736 +#define ORD_WIN32ENDENUMWINDOWS 737 +#define ORD_WIN32ENDPAINT 738 +#define ORD_WIN32ENUMCLIPBRDFMTS 739 +#define ORD_WIN32ENUMDLGITEM 740 +#define ORD_WIN32EQUALRECT 741 +#define ORD_WIN32EXCLUDEUPDATEREGION 742 +#define ORD_WIN32FILLRECT 743 +#define ORD_WIN32FINDATOM 744 +#define ORD_WIN32FLASHWINDOW 745 +#define ORD_WIN32FOCUSCHANGE 746 +#define ORD_WIN32FREEERRORINFO 748 +#define ORD_WIN32GETCLIPPS 749 +#define ORD_WIN32GETCURRENTTIME 750 +#define ORD_WIN32GETERRORINFO 751 +#define ORD_WIN32GETKEYSTATE 752 +#define ORD_WIN32GETLASTERROR 753 +#define ORD_WIN32GETMAXPOSITION 754 +#define ORD_WIN32GETMINPOSITION 755 +#define ORD_WIN32GETNEXTWINDOW 756 +#define ORD_WIN32GETPS 757 +#define ORD_WIN32GETPHYSKEYSTATE 758 +#define ORD_WIN32GETSCREENPS 759 +#define ORD_WIN32GETSYSBITMAP 760 +#define ORD_WIN32INSENDMSG 761 +#define ORD_WIN32INFLATERECT 762 +#define ORD_WIN32INITIALIZE 763 +#define ORD_WIN32INTERSECTRECT 764 +#define ORD_WIN32INVALIDATERECT 765 +#define ORD_WIN32INVALIDATEREGION 766 +#define ORD_WIN32INVERTRECT 767 +#define ORD_WIN32ISCHILD 768 +#define ORD_WIN32ISPHYSINPUTENABLED 769 +#define ORD_WIN32ISRECTEMPTY 770 +#define ORD_WIN32ISTHREADACTIVE 771 +#define ORD_WIN32ISWINDOW 772 +#define ORD_WIN32ISWINDOWENABLED 773 +#define ORD_WIN32ISWINDOWSHOWING 774 +#define ORD_WIN32ISWINDOWVISIBLE 775 +#define ORD_WIN32LOADACCELTABLE 776 +#define ORD_WIN32LOADLIBRARY 777 +#define ORD_WIN32LOADMENU 778 +#define ORD_WIN32LOADMESSAGE 779 +#define ORD_WIN32LOADPOINTER 780 +#define ORD_WIN32LOADSTRING 781 +#define ORD_WIN32LOCKVISREGIONS 782 +#define ORD_WIN32LOCKWINDOWUPDATE 784 +#define ORD_WIN32MAKEPOINTS 785 +#define ORD_WIN32MAKERECT 786 +#define ORD_WIN32MAPDLGPOINTS 787 +#define ORD_WIN32MAPWINDOWPOINTS 788 +#define ORD_WIN32MESSAGEBOX 789 +#define ORD_WIN32MSGSEMWAIT 790 +#define ORD_WIN32NEXTCHAR 791 +#define ORD_WIN32OFFSETRECT 792 +#define ORD_WIN32OPENCLIPBRD 793 +#define ORD_WIN32OPENWINDOWDC 794 +#define ORD_WIN32PREVCHAR 795 +#define ORD_WIN32PROCESSDLG 796 +#define ORD_WIN32PTINRECT 797 +#define ORD_WIN32QUERYACCELTABLE 798 +#define ORD_WIN32QUERYACTIVEWINDOW 799 +#define ORD_WIN32QUERYANCHORBLOCK 800 +#define ORD_WIN32QUERYATOMLENGTH 801 +#define ORD_WIN32QUERYATOMNAME 802 +#define ORD_WIN32QUERYATOMUSAGE 803 +#define ORD_WIN32QUERYCAPTURE 804 +#define ORD_WIN32QUERYCLASSNAME 805 +#define ORD_WIN32QUERYCLIPBRDDATA 806 +#define ORD_WIN32QUERYCLIPBRDFMTINFO 807 +#define ORD_WIN32QUERYCLIPBRDOWNER 808 +#define ORD_WIN32QUERYCLIPBRDVIEWER 809 +#define ORD_WIN32QUERYCP 810 +#define ORD_WIN32QUERYCPLIST 811 +#define ORD_WIN32QUERYCURSORINFO 812 +#define ORD_WIN32QUERYDESKTOPWINDOW 813 +#define ORD_WIN32QUERYDLGITEMSHORT 814 +#define ORD_WIN32QUERYDLGITEMTEXT 815 +#define ORD_WIN32QUERYDLGITEMTEXTLENGTH 816 +#define ORD_WIN32QUERYFOCUS 817 +#define ORD_WIN32QUERYMSGPOS 818 +#define ORD_WIN32QUERYMSGTIME 819 +#define ORD_WIN32QUERYOBJECTWINDOW 820 +#define ORD_WIN32QUERYPOINTER 821 +#define ORD_WIN32QUERYPOINTERINFO 822 +#define ORD_WIN32QUERYPOINTERPOS 823 +#define ORD_WIN32QUERYQUEUEINFO 824 +#define ORD_WIN32QUERYQUEUESTATUS 825 +#define ORD_WIN32QUERYSYSCOLOR 826 +#define ORD_WIN32QUERYSYSMODALWINDOW 827 +#define ORD_WIN32QUERYSYSPOINTER 828 +#define ORD_WIN32QUERYSYSVALUE 829 +#define ORD_WIN32QUERYSYSTEMATOMTABLE 830 +#define ORD_WIN32QUERYUPDATERECT 831 +#define ORD_WIN32QUERYUPDATEREGION 832 +#define ORD_WIN32QUERYVERSION 833 +#define ORD_WIN32QUERYWINDOW 834 +#define ORD_WIN32QUERYWINDOWDC 835 +#define ORD_WIN32QUERYWINDOWPOS 837 +#define ORD_WIN32QUERYWINDOWPROCESS 838 +#define ORD_WIN32QUERYWINDOWPTR 839 +#define ORD_WIN32QUERYWINDOWRECT 840 +#define ORD_WIN32QUERYWINDOWTEXT 841 +#define ORD_WIN32QUERYWINDOWTEXTLENGTH 842 +#define ORD_WIN32QUERYWINDOWULONG 843 +#define ORD_WIN32QUERYWINDOWUSHORT 844 +#define ORD_WIN32REGISTERUSERDATATYPE 845 +#define ORD_WIN32REGISTERUSERMSG 846 +#define ORD_WIN32RELEASEPS 848 +#define ORD_WIN32SCROLLWINDOW 849 +#define ORD_WIN32SETACCELTABLE 850 +#define ORD_WIN32SETACTIVEWINDOW 851 +#define ORD_WIN32SETCAPTURE 852 +#define ORD_WIN32SETCLASSMSGINTEREST 853 +#define ORD_WIN32SETCLIPBRDDATA 854 +#define ORD_WIN32SETCLIPBRDOWNER 855 +#define ORD_WIN32SETCLIPBRDVIEWER 856 +#define ORD_WIN32SETCP 857 +#define ORD_WIN32SETDLGITEMSHORT 858 +#define ORD_WIN32SETDLGITEMTEXT 859 +#define ORD_WIN32SETFOCUS 860 +#define ORD_WIN32SETMSGINTEREST 861 +#define ORD_WIN32SETMSGMODE 862 +#define ORD_WIN32SETMULTWINDOWPOS 863 +#define ORD_WIN32SETOWNER 864 +#define ORD_WIN32SETPARENT 865 +#define ORD_WIN32SETPOINTER 866 +#define ORD_WIN32SETPOINTERPOS 867 +#define ORD_WIN32SETRECT 868 +#define ORD_WIN32SETRECTEMPTY 869 +#define ORD_WIN32SETSYNCHROMODE 870 +#define ORD_WIN32SETSYSCOLORS 871 +#define ORD_WIN32SETSYSMODALWINDOW 872 +#define ORD_WIN32SETSYSVALUE 873 +#define ORD_WIN32SETWINDOWBITS 874 +#define ORD_WIN32SETWINDOWPOS 875 +#define ORD_WIN32SETWINDOWPTR 876 +#define ORD_WIN32SETWINDOWTEXT 877 +#define ORD_WIN32SETWINDOWULONG 878 +#define ORD_WIN32SETWINDOWUSHORT 879 +#define ORD_WIN32SHOWCURSOR 880 +#define ORD_WIN32SHOWPOINTER 881 +#define ORD_WIN32SHOWTRACKRECT 882 +#define ORD_WIN32SHOWWINDOW 883 +#define ORD_WIN32STARTTIMER 884 +#define ORD_WIN32STOPTIMER 885 +#define ORD_WIN32SUBSTITUTESTRINGS 886 +#define ORD_WIN32SUBTRACTRECT 887 +#define ORD_WIN32TERMINATE 888 +#define ORD_WIN32TRACKRECT 890 +#define ORD_WIN32UNIONRECT 891 +#define ORD_WIN32UPDATEWINDOW 892 +#define ORD_WIN32UPPER 893 +#define ORD_WIN32UPPERCHAR 894 +#define ORD_WIN32VALIDATERECT 895 +#define ORD_WIN32VALIDATEREGION 896 +#define ORD_WIN32WAITMSG 897 +#define ORD_WIN32WINDOWFROMDC 898 +#define ORD_WIN32WINDOWFROMID 899 +#define ORD_WIN32WINDOWFROMPOINT 900 +#define ORD_WIN32BROADCASTMSG 901 +#define ORD_WIN32POSTQUEUEMSG 902 +#define ORD_WIN32SENDDLGITEMMSG 903 +#define ORD_WIN32TRANSLATEACCEL 904 +#define ORD_WIN32CALLMSGFILTER 905 +#define ORD_WIN32CREATEFRAMECONTROLS 906 +#define ORD_WIN32CREATEMENU 907 +#define ORD_WIN32CREATESTDWINDOW 908 +#define ORD_WIN32CREATEWINDOW 909 +#define ORD_WIN32DEFDLGPROC 910 +#define ORD_WIN32DEFWINDOWPROC 911 +#define ORD_WIN32DISPATCHMSG 912 +#define ORD_WIN32DRAWTEXT 913 +#define ORD_WIN32GETDLGMSG 914 +#define ORD_WIN32GETMSG 915 +#define ORD_WIN32MSGMUXSEMWAIT 916 +#define ORD_WIN32MULTWINDOWFROMIDS 917 +#define ORD_WIN32PEEKMSG 918 +#define ORD_WIN32POSTMSG 919 +#define ORD_WIN32SENDMSG 920 +#define ORD_WIN32SETKEYBOARDSTATETABLE 921 +#define ORD_WIN32CREATEDLG 922 +#define ORD_WIN32DLGBOX 923 +#define ORD_WIN32LOADDLG 924 +#define ORD_WIN32QUERYCLASSINFO 925 +#define ORD_WIN32REGISTERCLASS 926 +#define ORD_WIN32RELEASEHOOK 927 +#define ORD_WIN32SETHOOK 928 +#define ORD_WIN32SUBCLASSWINDOW 929 +#define ORD_WIN32SETCLASSTHUNKPROC 930 +#define ORD_WIN32QUERYCLASSTHUNKPROC 931 +#define ORD_WIN32SETWINDOWTHUNKPROC 932 +#define ORD_WIN32QUERYWINDOWTHUNKPROC 933 +#define ORD_WIN32QUERYWINDOWMODEL 934 +#define ORD_WIN32SETDESKTOPBKGND 935 +#define ORD_WIN32QUERYDESKTOPBKGND 936 +#define ORD_WIN32POPUPMENU 937 +#define ORD_WIN32SETPRESPARAM 938 +#define ORD_WIN32QUERYPRESPARAM 939 +#define ORD_WIN32REMOVEPRESPARAM 940 +#define ORD_WIN32REALIZEPALETTE 941 +#define ORD_WIN32CREATEPOINTERINDIRECT 942 +#define ORD_WIN32SAVEWINDOWPOS 943 +#define ORD_WIN32GETERASEPS 952 +#define ORD_WIN32RELEASEERASEPS 953 +#define ORD_WIN32SETPOINTEROWNER 971 +#define ORD_WIN32STRETCHPOINTER 968 +#define ORD_WIN32SETERRORINFO 977 +#define ORD_WIN32WAITEVENTSEM 978 +#define ORD_WIN32REQUESTMUTEXSEM 979 +#define ORD_WIN32WAITMUXWAITSEM 980 + + +#ifndef INCL_32 +#error Prototypes are for 32-bit compiler only +#endif + +HAB (APIENTRY *p_WinInitialize)(ULONG flOptions); +BOOL (APIENTRY *p_WinTerminate)(HAB hab); +HMQ (APIENTRY *p_WinCreateMsgQueue)(HAB hab, LONG cmsg); +BOOL (APIENTRY *p_WinDestroyMsgQueue)(HMQ hmq); +BOOL (APIENTRY *p_WinEmptyClipbrd)(HAB hab); +BOOL (APIENTRY *p_WinOpenClipbrd)(HAB hab); +BOOL (APIENTRY *p_WinCloseClipbrd)(HAB hab); +BOOL (APIENTRY *p_WinSetClipbrdData)(HAB hab, ULONG ulData, ULONG fmt, ULONG rgfFmtInfo); +ULONG (APIENTRY *p_WinQueryClipbrdData)(HAB hab, ULONG fmt); + +static struct impentry { + ULONG ordinal; + PFN *pointer; +} imported_functions[] = { + { ORD_WIN32INITIALIZE, (PFN *) &p_WinInitialize }, + { ORD_WIN32TERMINATE, (PFN *) &p_WinTerminate }, + { ORD_WIN32CREATEMSGQUEUE, (PFN *) &p_WinCreateMsgQueue }, + { ORD_WIN32DESTROYMSGQUEUE,(PFN *) &p_WinDestroyMsgQueue }, + { ORD_WIN32EMPTYCLIPBRD, (PFN *) &p_WinEmptyClipbrd }, + { ORD_WIN32OPENCLIPBRD, (PFN *) &p_WinOpenClipbrd }, + { ORD_WIN32CLOSECLIPBRD, (PFN *) &p_WinCloseClipbrd }, + { ORD_WIN32SETCLIPBRDDATA, (PFN *) &p_WinSetClipbrdData }, + { ORD_WIN32QUERYCLIPBRDDATA,(PFN *)&p_WinQueryClipbrdData }, + { 0, 0 } +}; + +/* + * Load PMWIN.DLL and get pointers to all reqd PM functions + */ + +static BOOL loadDLL(void) { + static BOOL loaded = FALSE; + static BOOL loaded_ok = FALSE; + static HMODULE pmwin; + + char error[200]; + + if (loaded == TRUE) + return loaded_ok; + + loaded = TRUE; + + if (DosLoadModule((PSZ)error, sizeof(error), (PSZ)"PMWIN.DLL", &pmwin) == 0) { + struct impentry *imp; + + for (imp = imported_functions; imp->ordinal; imp++) + if (DosQueryProcAddr(pmwin, imp->ordinal, NULL, imp->pointer) != 0) + return FALSE; + + loaded_ok = TRUE; + } + + return loaded_ok; +} + +/* + AccessPmClipboard: + Purpose: perform all necessary PM stuff and open clipboard for access; + Return : TRUE on success, FALSE on error; + Note : on error, clipboard is released automatically. + + LeavePmClipboard: + Purpose: releases previously opened clipboard and clear all PM stuff + Return : none + */ + +static struct { + PPIB ppib; + HAB hab; + HMQ hmq; + ULONG savedtype; + BOOL opened; +} PmInfo; + +static void LeavePmClipboard(void) { + + if (PmInfo.opened) + p_WinCloseClipbrd(PmInfo.hab); + if (PmInfo.hmq) + p_WinDestroyMsgQueue(PmInfo.hmq); + if (PmInfo.hab) + p_WinTerminate(PmInfo.hab); + PmInfo.ppib->pib_ultype = PmInfo.savedtype; +} + +static BOOL AccessPmClipboard(void) { + PTIB ptib; + + if (loadDLL() == FALSE) { + DosBeep(100, 1500); + return FALSE; + } + + memset(&PmInfo, 0, sizeof(PmInfo)); + + // mutate into PM application for clipboard (Win**) functions access + DosGetInfoBlocks(&ptib, &PmInfo.ppib); + PmInfo.savedtype = PmInfo.ppib->pib_ultype; + PmInfo.ppib->pib_ultype = PROG_PM; + + if ((PmInfo.hab = p_WinInitialize(0)) != NULLHANDLE) { + if ((PmInfo.hmq = p_WinCreateMsgQueue(PmInfo.hab, 0)) != NULLHANDLE) { + if (p_WinOpenClipbrd(PmInfo.hab) == TRUE) { + PmInfo.opened = TRUE; + } + } + } + if (PmInfo.opened != TRUE) { + LeavePmClipboard(); + DosBeep(100, 1500); + } + return PmInfo.opened; +} + +int GetClipText(ClipData *cd) { + int rc = -1; + char *text; + + cd->fLen = 0; + cd->fChar = 0; + + if (AccessPmClipboard() != TRUE) + return rc; + + if ((text = (char *) p_WinQueryClipbrdData(PmInfo.hab, CF_TEXT)) != 0) { + cd->fLen = strlen(text); + cd->fChar = strdup(text); + rc = 0; + } + + LeavePmClipboard(); + return rc; +} + +int PutClipText(ClipData *cd) { + ULONG len; + void *text; + int rc = -1; + + if (AccessPmClipboard() != TRUE) + return rc; + + p_WinEmptyClipbrd(PmInfo.hab); + len = cd->fLen; + + if (len) { + DosAllocSharedMem((void **)&text, + 0, + len + 1, + PAG_READ | PAG_WRITE | PAG_COMMIT | OBJ_GIVEABLE); + strncpy((char *)text, cd->fChar, len + 1); + if (!p_WinSetClipbrdData(PmInfo.hab, (ULONG) text, CF_TEXT, CFI_POINTER)) + DosBeep(100, 1500); + else + rc = 0; + } + + LeavePmClipboard(); + return rc; +} diff --git a/src/clip_vio.cpp b/src/clip_vio.cpp new file mode 100644 index 0000000..49f0b41 --- /dev/null +++ b/src/clip_vio.cpp @@ -0,0 +1,103 @@ +/* clip_vio.cpp + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +// OS/2 does not allow VIO programs to use the clipboard :-( + +#include "fte.h" +#include "clip.h" + +#define INCL_DOS +#include +#include +#include + +#define SEM_PREFIX "\\SEM32\\PMCLIPS\\" +#define MEM_PREFIX "\\SHAREMEM\\PMCLIPS\\" + +#define CMD_GET 1 +#define CMD_PUT 2 + +static HMTX hmtxSyn; +static HEV hevGet; +static HEV hevPut; +static HEV hevEnd; + +int GetClipText(ClipData *cd) { + int rc; + ULONG PostCount; + char *mem; + + rc = DosOpenMutexSem(SEM_PREFIX "CLIPSYN", &hmtxSyn); + if (rc != 0) return -1; + rc = DosOpenEventSem(SEM_PREFIX "CLIPGET", &hevGet); + if (rc != 0) return -1; +/* rc = DosOpenEventSem(SEM_PREFIX "CLIPPUT", &hevPut);*/ +/* if (rc != 0) return -1;*/ + rc = DosOpenEventSem(SEM_PREFIX "CLIPEND", &hevEnd); + if (rc != 0) return -1; + + DosRequestMutexSem(hmtxSyn, SEM_INDEFINITE_WAIT); + DosResetEventSem(hevEnd, &PostCount); + DosPostEventSem(hevGet); + DosWaitEventSem(hevEnd, SEM_INDEFINITE_WAIT); + if (0 == DosGetNamedSharedMem((void **)&mem, MEM_PREFIX "CLIPDATA", PAG_READ | PAG_WRITE)) { + cd->fLen = *(ULONG*)mem; + cd->fChar = strdup(mem + 4); + DosFreeMem(mem); + } else { + cd->fLen = 0; + cd->fChar = 0; + } + DosPostEventSem(hevGet); + DosReleaseMutexSem(hmtxSyn); +/* DosCloseEventSem(hevPut);*/ + DosCloseEventSem(hevGet); + DosCloseEventSem(hevEnd); + DosCloseMutexSem(hmtxSyn); + return 0; +} + +int PutClipText(ClipData *cd) { + int rc; + ULONG PostCount; + char *mem; + + rc = DosOpenMutexSem(SEM_PREFIX "CLIPSYN", &hmtxSyn); + if (rc != 0) return -1; +/* rc = DosOpenEventSem(SEM_PREFIX "CLIPGET", &hevGet);*/ +/* if (rc != 0) return -1;*/ + rc = DosOpenEventSem(SEM_PREFIX "CLIPPUT", &hevPut); + if (rc != 0) return -1; + rc = DosOpenEventSem(SEM_PREFIX "CLIPEND", &hevEnd); + if (rc != 0) return -1; + + DosRequestMutexSem(hmtxSyn, SEM_INDEFINITE_WAIT); + DosResetEventSem(hevEnd, &PostCount); + if (0 == DosAllocSharedMem((void **)&mem, + MEM_PREFIX "CLIPDATA", + cd->fLen + 5, + PAG_COMMIT | PAG_READ | PAG_WRITE)) + { + ULONG L = cd->fLen; + memcpy((void *)mem, (void *)&L, 4); + strcpy(mem + 4, cd->fChar); + } + DosPostEventSem(hevPut); + DosWaitEventSem(hevEnd, SEM_INDEFINITE_WAIT); + DosPostEventSem(hevPut); + DosReleaseMutexSem(hmtxSyn); + DosCloseEventSem(hevPut); +/* DosCloseEventSem(hevGet); */ + DosCloseEventSem(hevEnd); + DosCloseMutexSem(hmtxSyn); + if (mem) + DosFreeMem(mem); + return 0; + +} diff --git a/src/clip_x11.cpp b/src/clip_x11.cpp new file mode 100644 index 0000000..24fceac --- /dev/null +++ b/src/clip_x11.cpp @@ -0,0 +1,83 @@ +/* clip_x11.cpp + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#include "fte.h" + +int GetXSelection(int *len, char **data); +int SetXSelection(int len, char *data); + +int GetPMClip() { + char *data; + int len; + int i,j, l, dx; + EPoint P; + + if (GetXSelection(&len, &data) == 0) { + SSBuffer->Clear(); + j = 0; + l = 0; + + for (i = 0; i < len; i++) { + if (data[i] == '\n') { + SSBuffer->AssertLine(l); + P.Col = 0; P.Row = l++; + dx = 0; + if ((i > 0) && (data[i-1] == '\r')) dx++; + SSBuffer->InsertLine(P, i - j - dx, data + j); + j = i + 1; + } + } + if (j < len) { // remainder + i = len; + SSBuffer->AssertLine(l); + P.Col = 0; P.Row = l++; + dx = 0; + if ((i > 0) && (data[i-1] == '\r')) dx++; + SSBuffer->InsText(P.Row, P.Col, i - j - dx, data + j); + j = i + 1; + } + free(data); + return 1; + } + return 0; +} + +int PutPMClip() { + PELine L; + char *p = NULL; + int rc = 0; + int l = 0; + + for (int i = 0; i < SSBuffer->RCount; i++) { + L = SSBuffer->RLine(i); + char *n = (char *)realloc(p, l + L->Count + 1); + if (n != NULL) { + for(int j = 0; j < L->Count; j++) { + if ((j < (L->Count - 1)) && (L->Chars[j + 1] == '\b')) + j++; + else + n[l++] = L->Chars[j]; + } + if (i < SSBuffer->RCount - 1) + n[l++] = '\n'; + else + n[l] = 0; + } else + break; + p = n; // if p already contains some address it will be freed + } + + if (p != NULL) { + // remove some 'UNWANTED' characters - sequence XX 0x08 YY -> YY + // this makes usable cut&paste from manpages + rc = (SetXSelection(l, p) == 0); + free(p); + } + return (rc)?1:0; +} diff --git a/src/clipprog.cpp b/src/clipprog.cpp new file mode 100644 index 0000000..7109eae --- /dev/null +++ b/src/clipprog.cpp @@ -0,0 +1,73 @@ +/* clipprog.cpp + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + + +#define INCL_DOS +#define INCL_PM +#include +#include +#include +#include +#include + +#define SEM_PREFIX "\\SEM32\\PMCLIPS\\" +#define MEM_PREFIX "\\SHAREMEM\\PMCLIPS\\" + +#define CMD_GET 1 +#define CMD_PUT 2 + +HAB hab; +HMQ hmq; +QMSG qmsg; +HMTX hmtxSyn; +HEV hevGet; +HEV hevPut; +HEV hevEnd; +HMUX hmuxWait; + +void clipsrv(void *foo) { + HAB hab; + HMQ hmq; + ULONG Cmd; + ULONG len; + char *text; + void *shmem = "the text"; + + hab = NULLHANDLE; + + if ((WinOpenClipbrd(hab) == TRUE) && + ((text = (char *) WinQueryClipbrdData(hab, CF_TEXT)) != 0)) + { + DosGetSharedMem(text, PAG_READ); + len = strlen(text); + puts(text); + } + WinCloseClipbrd(hab); + + len = strlen(shmem); + if (len) { + DosAllocSharedMem((void **)&text, + 0, + len + 1, + PAG_WRITE | PAG_COMMIT | OBJ_GIVEABLE | OBJ_GETTABLE); + strcpy(text, shmem); + } + + if (WinOpenClipbrd(hab) == TRUE) { + if (!WinSetClipbrdData(hab, (ULONG) text, CF_TEXT, CFI_POINTER)) + DosBeep(100, 1500); + WinCloseClipbrd(hab); + } +} + +int main() { + clipsrv(NULL); + return 0; +} + diff --git a/src/clipserv.cpp b/src/clipserv.cpp new file mode 100644 index 0000000..f16fbae --- /dev/null +++ b/src/clipserv.cpp @@ -0,0 +1,185 @@ +/* clipserv.cpp + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#define INCL_DOS +#define INCL_PM +#include +#include +#include +#include +#include +#include "sysdep.h" + +#define SEM_PREFIX "\\SEM32\\PMCLIPS\\" +#define MEM_PREFIX "\\SHAREMEM\\PMCLIPS\\" + +#define CMD_GET 1 +#define CMD_PUT 2 + +HAB hab; +HMQ hmq; +QMSG qmsg; +HMTX hmtxSyn; +HEV hevGet; +HEV hevPut; +HEV hevEnd; +HMUX hmuxWait; + +void _LNK_CONV clipsrv(void *foo) { + HAB hab; + HMQ hmq; + + hab = WinInitialize(0); + hmq = WinCreateMsgQueue(hab, 0); + + while (1) { + ULONG ulPostCount; + ULONG Cmd; + ULONG len; + char *text; + void *shmem; + + WinWaitMuxWaitSem(hmuxWait, SEM_INDEFINITE_WAIT, &Cmd); + switch (Cmd) { + case CMD_GET: + DosResetEventSem(hevGet, &ulPostCount); + + shmem = 0; + if ((WinOpenClipbrd(hab) == TRUE) && + ((text = (char *) WinQueryClipbrdData(hab, CF_TEXT)) != 0)) + { + len = strlen(text); + puts(text); + if (0 == DosAllocSharedMem(&shmem, + MEM_PREFIX "CLIPDATA", + len + 5, + PAG_COMMIT | PAG_WRITE | PAG_READ)) + { + memcpy(shmem, (void *)&len, 4); + memcpy((void *)(((char *)shmem) + sizeof(ULONG)), text, len + 1); + } else { + DosBeep(200, 500); + } + } else { + /*DosBeep(100, 1500);*/ + len = 0; + if (0 == DosAllocSharedMem(&shmem, + MEM_PREFIX "CLIPDATA", + 4, + PAG_COMMIT | PAG_WRITE | PAG_READ)) + { + memcpy(shmem, (void *)&len, 4); + } + } + WinCloseClipbrd(hab); + DosPostEventSem(hevEnd); + DosWaitEventSem(hevGet, SEM_INDEFINITE_WAIT); + DosResetEventSem(hevGet, &ulPostCount); + if (shmem) DosFreeMem(shmem); + break; + + case CMD_PUT: + DosResetEventSem(hevPut, &ulPostCount); + + if (0 == DosGetNamedSharedMem(&shmem, + MEM_PREFIX "CLIPDATA", + PAG_READ | PAG_WRITE)) + { + if (WinOpenClipbrd(hab) == TRUE) { + WinEmptyClipbrd(hab); + len = strlen((char *)shmem + 4); + if (len) { + DosAllocSharedMem((void **)&text, + 0, + len + 1, + PAG_WRITE | PAG_COMMIT | OBJ_GIVEABLE); + strcpy(text, ((char *)shmem) + 4); + if (!WinSetClipbrdData(hab, (ULONG) text, CF_TEXT, CFI_POINTER)) + DosBeep(100, 1500); + + } + WinCloseClipbrd(hab); + } else { + DosBeep(1500, 3500); + } + } else { + DosBeep(500, 7500); + } + DosPostEventSem(hevEnd); + DosWaitEventSem(hevPut, SEM_INDEFINITE_WAIT); + DosResetEventSem(hevPut, &ulPostCount); + if (shmem) DosFreeMem(shmem); + break; + } + } + WinDestroyMsgQueue(hmq); + WinTerminate(hab); +} + +int main() { + SEMRECORD sem[2]; + int rc; + + rc = DosCreateMutexSem(SEM_PREFIX "CLIPSYN", + &hmtxSyn, + 0, + 0); + if (rc != 0) return 1; + puts("CLIPSYN"); + + rc = DosCreateEventSem(SEM_PREFIX "CLIPEND", + &hevEnd, + 0, + 0); + if (rc != 0) return 1; + puts("CLIPEND"); + + rc = DosCreateEventSem(SEM_PREFIX "CLIPGET", + &hevGet, + 0, + 0); + if (rc != 0) return 1; + puts("CLIPGET"); + + rc = DosCreateEventSem(SEM_PREFIX "CLIPPUT", + &hevPut, + 0, + 0); + if (rc != 0) return 1; + puts("CLIPPUT"); + + sem[0].hsemCur = (PULONG) hevGet; + sem[0].ulUser = CMD_GET; + sem[1].hsemCur = (PULONG) hevPut; + sem[1].ulUser = CMD_PUT; + + rc = DosCreateMuxWaitSem(0, + &hmuxWait, + 2, + sem, + DCMW_WAIT_ANY); + if (rc != 0) return 1; + puts("CLIPMUX"); + + hab = WinInitialize(0); + + hmq = WinCreateMsgQueue(hab, 0); +#if defined(__EMX__) || defined(__TOS_OS2__) + _beginthread(clipsrv, NULL, 8192, 0); +#else + _beginthread(clipsrv, 8192, 0); +#endif + while (WinGetMsg (hab, &qmsg, 0, 0, 0)) + WinDispatchMsg (hab, &qmsg); + + + WinDestroyMsgQueue(hmq); + WinTerminate(hab); + return 0; +} diff --git a/src/clipserv.def b/src/clipserv.def new file mode 100644 index 0000000..23ae27a --- /dev/null +++ b/src/clipserv.def @@ -0,0 +1,3 @@ +NAME clipserv WINDOWAPI +DESCRIPTION 'FTE Clipboard access server for VIO' +STACKSIZE 49152 diff --git a/src/cliputil.cpp b/src/cliputil.cpp new file mode 100644 index 0000000..b05ca07 --- /dev/null +++ b/src/cliputil.cpp @@ -0,0 +1,50 @@ +/* cliputil.cpp + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#include "clip.h" +#include +#include +#include + +#define MAXCLIPTEXT 256 * 1024 /* just for demo */ + +char buffer[MAXCLIPTEXT]; + +int main(int argc, char **argv) { + ClipData cd; + int i; + + if ((argc == 2) && (strcmp(argv[1], "-s") == 0)) { + cd.fLen = fread(buffer, 1, MAXCLIPTEXT, stdin); + cd.fChar = buffer; + if (PutClipText(&cd) == -1) { + fprintf(stderr, "Coult not set clipboard text\n"); + return 1; + } + } else if (argc == 1) { + if (GetClipText(&cd) == 0) { + if ((cd.fLen != 0) && cd.fChar) { + printf("%s", cd.fChar); + } + } else { + fprintf(stderr, "Could not get clipboard text\n"); + return 1; + } + } else { + fprintf(stderr, + "Usage: %s {-s}\n" + "\n" + "Examples:\n" + " cliputil | more\n" + " dir | cliputil -s\n", + argv[0]); + return 1; + } + return 0; +} diff --git a/src/cliputil.def b/src/cliputil.def new file mode 100644 index 0000000..b8e55df --- /dev/null +++ b/src/cliputil.def @@ -0,0 +1,3 @@ +NAME ClipUtil WINDOWCOMPAT +DESCRIPTION 'Clipboard Utility - get/put clipboard text from command line' +STACKSIZE 49152 diff --git a/src/commands.cpp b/src/commands.cpp new file mode 100644 index 0000000..d045d4b --- /dev/null +++ b/src/commands.cpp @@ -0,0 +1,30 @@ +/* commands.cpp + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#include "fte.h" + +int GetDefaultDirectory(EModel *M, char *Path, int MaxLen) { + if (M) + M->GetPath(Path, MaxLen); + if (!M || Path[0] == 0) + if (ExpandPath(".", Path) == -1) + return 0; + SlashDir(Path); + return 1; +} + +int SetDefaultDirectory(EModel *M) { + char Path[MAXPATH]; + + if (GetDefaultDirectory(M, Path, sizeof(Path)) == 0) + return 0; + if (ChangeDir(Path) == -1) + return 0; + return 1; +} diff --git a/src/compkeys.cpp b/src/compkeys.cpp new file mode 100644 index 0000000..052a3e1 --- /dev/null +++ b/src/compkeys.cpp @@ -0,0 +1,457 @@ +/* + * compkeys.cpp + * + * Copyright (c) 1998 by István Váradi + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#include +#include +#include +#include + +#include "console.h" +#include "conkbd.h" + +#define FTESL_KBDCTRL(x) ( x-'a'+ 1) + +static unsigned get_linux_keycode(TKeyCode kcode) +{ + static unsigned lnxkeycodes[] = { + /* 32 */ + 57, 2, 40, 4, 5, 6, 8, 40, + + /* 40 */ + 10, 11, 9, 13, 51, 12, 52, 53, + + /* 48 */ + 11, 2, 3, 4, 5, 6, 7, 8, + + /* 56 */ + 9 , 10, 39, 39, 51, 13, 52, 53, + + /* 64 */ + 3 , 30, 48, 46, 32, 18, 33, 34, + + /* 72 */ + 35, 23, 36, 37, 38, 50, 49, 24, + + /* 80 */ + 25, 16, 19, 31, 20, 22, 47, 17, + + /* 88 */ + 45, 21, 44, 26, 86, 27, 7, 12, + + /* 96 */ + 43, 30, 48, 46, 32, 18, 33, 34, + + /* 104 */ + 35, 23, 36, 37, 38, 50, 49, 24, + + /* 112 */ + 25, 16, 19, 31, 20, 22, 47, 17, + + /* 120 */ + 45, 21, 44, 26, 86, 27, 43, 0, + }; + + TKeyCode key = keyCode(kcode)|(kcode&kfGray); + + switch(key) { + case kbF1: + case kbF2: + case kbF3: + case kbF4: + case kbF5: + case kbF6: + case kbF7: + case kbF8: + case kbF9: + case kbF10: + return 59+key-kbF1; + break; + case kbF11: + return 87; + break; + case kbF12: + return 88; + break; + case kbHome: + return 102; + break; + case kbEnd: + return 107; + break; + case kbPgUp: + return 104; + break; + case kbPgDn: + return 109; + break; + case kbIns: + return 110; + break; + case kbDel: + return 111; + break; + case kbUp: + return 103; + break; + case kbDown: + return 108; + break; + case kbLeft: + return 105; + break; + case kbRight: + return 106; + break; + case kbEnter: + return 28; + break; + case kbEsc: + return 1; + break; + case kbBackSp: + return 14; + break; + case kbSpace: + return 57; + break; + case kbTab: + return 15; + break; + case kbCenter: + return 76; + break; + case kfGray|'/': + return 98; + break; + case kfGray|'*': + return 55; + break; + case kfGray|'+': + return 78; + break; + case kfGray|'-': + return 74; + break; + case kfGray|kbEnter: + return 96; + break; + case kfGray|'.': + return 83; + break; + case kfGray|'7': + case kfGray|kbHome: + return 71; + break; + case kfGray|'8': + case kfGray|kbUp: + return 72; + break; + case kfGray|'9': + case kfGray|kbPgUp: + return 73; + break; + case kfGray|'4': + case kfGray|kbLeft: + return 75; + break; + case kfGray|'5': + return 76; + break; + case kfGray|'6': + case kfGray|kbRight: + return 77; + break; + case kfGray|'1': + case kfGray|kbEnd: + return 79; + break; + case kfGray|'2': + case kfGray|kbDown: + return 80; + break; + case kfGray|'3': + case kfGray|kbPgDn: + return 81; + break; + default: + if (key<128 && key>32) return lnxkeycodes[key-32]; + else return 0; + } +} + +typedef struct keymapper +{ + TKeyCode kcode; + const char* kname; +} keymapper; + +static keymapper speckeymap[]={ + { kbHome, "Home" }, + { kbEnd, "End" }, + { kbPgUp, "PgUp" }, + { kbPgDn, "PgDn" }, + { kbIns, "Ins" }, + { kbDel, "Del" }, + { kbUp, "Up" }, + { kbDown, "Down" }, + { kbLeft, "Left" }, + { kbRight, "Right" }, + { kbEnter, "Enter" }, + { kbEsc, "Esc" }, + { kbBackSp, "BackSp" }, + { kbSpace, "Space" }, + { kbTab, "Tab" }, + { kbCenter, "Center" }, +}; + +TKeyCode ftesl_getkeycode(const char* key) +{ + TKeyCode kcode = 0; + + if ( (*key)=='\0') return 0; + + while (*(key+1)=='+') { + switch (*key) { + case 'A': + kcode|=kfAlt; break; + case 'C': + kcode|=kfCtrl; break; + case 'S': + kcode|=kfShift; break; + case 'G': + kcode|=kfGray; break; + default: + return 0; + break; + } + key+=2; + } + + if ( (*key)=='\0') return 0; + + if ( *(key+1)=='\0') { + kcode|=*(unsigned char *)key; + return kcode; + } + + for(unsigned i=0; i='1' && *key<='9' ) { + if ( *key == '1' && *(key+1)!='\0' ) { + key++; + switch (*key) { + case '1': + kcode|=kbF11; + break; + case '2': + kcode|=kbF12; + break; + default: + return 0; + break; + } + return kcode; + } + kcode|=kbF1+(*key-'1'); + return kcode; + } + } + + return 0; +} + +int ftesl_get_ctrlcode(TKeyCode key) +{ + TKeyCode kcode = keyCode(key); + + switch(kcode) { + case kbUp: + return FTESL_KBDCTRL('u'); + case kbDown: + return FTESL_KBDCTRL('d'); + case kbLeft: + return FTESL_KBDCTRL('l'); + case kbRight: + return FTESL_KBDCTRL('r'); + case kbCenter: + return FTESL_KBDCTRL('x'); + case kbHome: + return FTESL_KBDCTRL('b'); + case kbEnd: + return FTESL_KBDCTRL('e'); + case kbPgUp: + return FTESL_KBDCTRL('p'); + case kbPgDn: + return FTESL_KBDCTRL('n'); + case kbIns: + return FTESL_KBDCTRL('q'); + case kbDel: + return FTESL_KBDCTRL('z'); + case kbBackSp: + return FTESL_KBDCTRL('h'); + case kbTab: + return FTESL_KBDCTRL('i'); + case kbEnter: + return FTESL_KBDCTRL('m'); + } + if (kcode>=kbF1 && kcode<=kbF12) return FTESL_KBDCTRL('f'); + else return (int)kcode; + +} + + +int main(int argc, char* argv[]) +{ + FILE* fin; + FILE* fout; + char finname[255]; + char foutname[255]; + char linebuf[256]; + char* lptr; + char keyspecbuf[32]; + char* bufptr; + int err = 0; + unsigned linecnt = 0; + unsigned strcnt = 0; + //int opt; + + finname[0] = '\0'; + foutname[0] = '\0'; + + printf("Linux keymap compiler for SLang FTE, Copyright (c) 1998 by István Váradi\n\n"); + + if (argc<3) { + fprintf(stderr, "Usage: compkeys infile outfile\n\n"); + fprintf(stderr, " where:\n"); + fprintf(stderr, " infile: the file with the list of the keys\n"); + fprintf(stderr, " outfile: the name of the output keymap file\n"); + exit(-2); + } + + strcpy(finname, argv[1]); + strcpy(foutname, argv[2]); + + fin = fopen(finname, "rt"); + + if (fin==NULL) { + fprintf(stderr, "Can't open input file '%s' for reading.\n", finname); + return -1; + } + + fout = fopen(foutname, "wb"); + + if (fout==NULL) { + fprintf(stderr, "Can't open output file '%s' for writing.\n", foutname); + fclose(fin); + return -1; + } + + + printf("Compiling from '%s' into '%s'.\n", finname, foutname); + + fprintf(fout, "############################\n"); + fprintf(fout, "# Keytable to use with FTE #\n"); + fprintf(fout, "# generated by 'compkeys' #\n"); + fprintf(fout, "############################\n\n"); + + err = 0; + while(!err && fgets(linebuf, sizeof(linebuf), fin)==linebuf) { + linecnt++; + lptr = linebuf; + while(!err) { + while(*lptr!='\0' && strchr(" \t", *lptr)!=NULL) lptr++; + if (*lptr=='#' || *lptr=='\0' || *lptr=='\n') break; + + bufptr=keyspecbuf; + + while(*lptr!='\0' && strchr(" \t\n", *lptr)==NULL) + *(bufptr++)=*(lptr++); + *(bufptr++)='\0'; + + TKeyCode kcode = ftesl_getkeycode(keyspecbuf), kcode1; + + if (kcode==0) { + err = 2; + } else { + + fprintf(fout, "\n# %s\n", keyspecbuf); + if (kcode&kfShift) fprintf(fout, "shift "); + if (kcode&kfCtrl) fprintf(fout, "control "); + if (kcode&kfAlt) fprintf(fout, "alt "); + fprintf(fout, "keycode %3u = F%u\n", + get_linux_keycode(kcode), 100+strcnt); + fprintf(fout, "string F%u = \"\\033", 100+strcnt); + if (kcode&kfShift) fprintf(fout, "\\023"); + if (kcode&kfCtrl) fprintf(fout, "\\003"); + if (kcode&kfAlt) fprintf(fout, "\\001"); + + int ccode = ftesl_get_ctrlcode(kcode); + fprintf(fout, "\\%03o", ccode); + + + if (ccode==FTESL_KBDCTRL('f')) { + kcode1 = keyCode(kcode); + switch(kcode1) { + case kbF1: + case kbF2: + case kbF3: + case kbF4: + case kbF5: + case kbF6: + case kbF7: + case kbF8: + case kbF9: + fprintf(fout, "%c", (int)'1'+int(kcode1-kbF1)); + break; + case kbF10: + fprintf(fout, "0"); break; + case kbF11: + fprintf(fout, "a"); break; + case kbF12: + fprintf(fout, "b"); break; + } + } + + fprintf(fout, "\"\n"); + strcnt++; + } + } + } + + fclose(fout); + fclose(fin); + + if (err) { + fprintf(stderr, "line %u: ", linecnt); + switch (err) { + case 1: + fprintf(stderr, "syntax error"); + break; + case 2: + fprintf(stderr, "invalid key specification: '%s'", + keyspecbuf); + } + fprintf(stderr, "\n"); + remove(foutname); + } else { + printf("\nDone.\n"); + } + + if (err) return -1; else return 0; +} + + \ No newline at end of file diff --git a/src/con_dosx.cpp b/src/con_dosx.cpp new file mode 100644 index 0000000..18207f6 --- /dev/null +++ b/src/con_dosx.cpp @@ -0,0 +1,1145 @@ +/* con_dosx.cpp + * + * Copyright (c) 1994-1996, Marko Macek + * Free 1996 F.Jalvingh + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +// include + +#include +#include +#include +#include +#include +#ifdef DJGPP +#include +#endif + +#include "sysdep.h" +#include "console.h" +#include "gui.h" + +#include +#include +#include "port.h" // DOS portability calls, + +#define MAX_PIPES 4 +#define PIPE_BUFLEN 4096 + +typedef struct { + int used; + int id; +// int reading; + int stopped; +// TID tid; +// HMTX Access; +// HEV ResumeRead; +// HEV NewData; +// char *buffer; +// int buflen; +// int bufused; +// int bufpos; + EModel *notify; +// char *Command; +// int RetCode; +// int DoTerm; + FILE *fp; +} GPipe; + +static GPipe Pipes[MAX_PIPES] = { + { 0 }, { 0 }, { 0 }, { 0 } +}; + + + +#if defined(__DJGPP__) + +// adapted from djgpp library source - redirects stderr as well as stdout +// Original author: pacetti@fl-ngnet.army.mil + +#include +#include +#include +#include +#include +#include + +/* hold file pointer, descriptor, command, mode, temporary file name, + and the status of the command */ +struct pipe_list { + FILE *fp; + int fd; + int exit_status; + char *command, mode[10], temp_name[L_tmpnam]; + struct pipe_list *next; +}; + +/* static, global list pointer */ +static struct pipe_list *pl = NULL; + +static FILE * +xpopen (const char *cm, const char *md) /* program name, pipe mode */ +{ + struct pipe_list *l1, *l2; + + /* make new node */ + if ((l1 = (struct pipe_list *) malloc (sizeof (struct pipe_list))) == NULL) + return NULL; + + /* zero out elements to we'll get here */ + l1->fd = 0; + l1->fp = NULL; + l1->next = NULL; + + /* if empty list - just grab new node */ + if (!pl) + pl = l1; + else + { + /* otherwise, find last node in list */ + ++(l1->fd); + l2 = pl; + while (l2->next) + { + ++(l1->fd); + l2 = l2->next; + }; + /* add new node to list */ + l2->next = l1; + } + + /* stick in elements we know already */ + l1->exit_status = -1; + strcpy (l1->mode, md); + if (tmpnam (l1->temp_name) == NULL) + return NULL; + + /* if can save the program name, build temp file */ + if ((l1->command = (char *) malloc(strlen(cm)+1))) + { + strcpy(l1->command, cm); + /* if caller wants to read */ + if (l1->mode[0] == 'r') + { +#if 1 + int fd2 = -1; +#endif + /* dup stdout */ + if ((l1->fd = dup (fileno (stdout))) == EOF) + l1->fp = NULL; + else if (!(l1->fp = freopen (l1->temp_name, "wb", stdout))) + l1->fp = NULL; +#if 1 + /* dup stderr */ + else if ((fd2 = dup (STDERR_FILENO)) == EOF) + l1->fp = NULL; + /* redirect stderr to new stdout */ + else if (dup2(fileno(l1->fp),STDERR_FILENO) == EOF) + l1->fp = NULL; +#endif + else + /* exec cmd */ + if ((l1->exit_status = system (cm)) == EOF) + l1->fp = NULL; + /* reopen real stdout */ + if (dup2 (l1->fd, fileno (stdout)) == EOF) + l1->fp = NULL; + else + /* open file for reader */ + l1->fp = fopen (l1->temp_name, l1->mode); + close(l1->fd); +#if 1 + /* restore stderr */ + if (fd2 >= 0) { + (void) dup2(fd2, STDERR_FILENO); + (void) close(fd2); + } +#endif + } + else + /* if caller wants to write */ + if (l1->mode[0] == 'w') + /* open temp file */ + l1->fp = fopen (l1->temp_name, l1->mode); + else + /* unknown mode */ + l1->fp = NULL; + } + return l1->fp; /* return == NULL ? ERROR : OK */ +} + +static int +xpclose (FILE *pp) +{ + struct pipe_list *l1, *l2; /* list pointers */ + int retval=0; /* function return value */ + + /* if pointer is first node */ + if (pl->fp == pp) + { + /* save node and take it out the list */ + l1 = pl; + pl = l1->next; + } + else + /* if more than one node in list */ + if (pl->next) + { + /* find right node */ + for (l2 = pl, l1 = pl->next; l1; l2 = l1, l1 = l2->next) + if (l1->fp == pp) + break; + + /* take node out of list */ + l2->next = l1->next; + } + else + return -1; + + /* if FILE not in list - return error */ + if (l1->fp == pp) + { + /* close the (hopefully) popen()ed file */ + fclose (l1->fp); + + /* if pipe was opened to write */ + if (l1->mode[0] == 'w') + { + /* dup stdin */ + if ((l1->fd = dup (fileno (stdin))) == EOF) + retval = -1; + else + /* open temp stdin */ + if (!(l1->fp = freopen (l1->temp_name, "rb", stdin))) + retval = -1; + else + /* exec cmd */ + if ((retval = system (l1->command)) != EOF) + { + /* reopen stdin */ + if (dup2 (l1->fd, fileno (stdin)) == EOF) + retval = -1; + } + close(l1->fd); + } + else + /* if pipe was opened to read, return the exit status we saved */ + if (l1->mode[0] == 'r') + retval = l1->exit_status; + else + /* invalid mode */ + retval = -1; + } + remove (l1->temp_name); /* remove temporary file */ + free (l1->command); /* dealloc memory */ + free (l1); /* dealloc memory */ + l1 = NULL; /* make pointer bogus */ + + return retval; /* retval==0 ? OK : ERROR */ +} + +#endif /* defined(__DJGPP__) */ + + + +static long MouseAutoDelay = 400; +static long MouseAutoRepeat = 5; +static long MouseMultiClick = 300; + +static int Initialized = 0; +static int MousePresent = 0; +static int CursorVisible = 1; /* 1 means visible */ +static int MouseVisible = 0; /* 0 means hidden */ +static TEvent MouseEv = { evNone }; +static TEvent EventBuf = { evNone }; +//static HMOU MouseHandle = 0; +//static KBDINFO SaveKbdState; + +// misc + +static void DrawCursor(int Show) { +} + +static void DrawMouse(int Show) +{ + if (!MousePresent) return; + if (Show) + MOUSCursen(TRUE); + else + MOUSCursen(FALSE); +} + +static struct { // TransCharScan + unsigned short CharScan; + TKeyCode KeyCode; +} TransCharScan[] = { + { 0x0100, kbEsc }, { 0x011B, kbEsc }, + { 0x1C0D, kbEnter }, { 0x1C0A, kbEnter }, + { 0x1C00, kbEnter }, { 0xE00D, kbEnter | kfGray }, + { 0xA600, kbEnter | kfGray }, { 0xE00A, kbEnter | kfGray }, + { 0x0E08, kbBackSp }, { 0x0E7F, kbBackSp }, + { 0x0E00, kbBackSp }, { 0x0F09, kbTab }, + { 0x9400, kbTab }, { 0xA500, kbTab }, + { 0x0F00, kbTab }, { 0x4E00, '+' | kfGray }, + { 0x9000, '+' | kfGray }, { 0x4E2B, '+' | kfGray }, + { 0x4A00, '-' | kfGray }, { 0x8E00, '-' | kfGray }, + { 0x4A2D, '-' | kfGray }, { 0x3700, '*' | kfGray }, + { 0x9600, '*' | kfGray }, { 0x372A, '*' | kfGray }, + { 0xE02F, '/' | kfGray }, { 0xA400, '/' | kfGray }, + { 0x9500, '/' | kfGray }, { 0x0300, 0 } +}; + +static struct { // TransScan + int ScanCode; + TKeyCode KeyCode; +} TransScan[] = { + { 0x78, '1' }, { 0x79, '2' }, { 0x7A, '3' }, { 0x7B, '4' }, { 0x7C, '5' }, + { 0x7D, '6' }, { 0x7E, '7' }, { 0x7F, '8' }, { 0x80, '9' }, { 0x81, '0' }, + + { 0x10, 'Q' }, { 0x11, 'W' }, { 0x12, 'E' }, { 0x13, 'R' }, { 0x14, 'T' }, + { 0x15, 'Y' }, { 0x16, 'U' }, { 0x17, 'I' }, { 0x18, 'O' }, { 0x19, 'P' }, + + { 0x1E, 'A' }, { 0x1F, 'S' }, { 0x20, 'D' }, { 0x21, 'F' }, { 0x22, 'G' }, + { 0x23, 'H' }, { 0x24, 'J' }, { 0x25, 'K' }, { 0x26, 'L' }, + + { 0x2C, 'Z' }, { 0x2D, 'X' }, { 0x2E, 'C' }, { 0x2F, 'V' }, { 0x30, 'B' }, + { 0x31, 'N' }, { 0x32, 'M' }, + + { 0x29, '`' }, { 0x82, '-' }, { 0x83, '=' }, { 0x2B, '\\' }, { 0x1A, '[' }, + { 0x1B, ']' }, { 0x27, ';' }, { 0x28, '\'' }, { 0x33, ',' }, { 0x34, '.' }, + { 0x35, '/' }, { 0x37, '*' }, { 0x4E, '+' }, { 0x4A, '-' }, + + { 0x3B, kbF1 }, { 0x3C, kbF2 }, { 0x3D, kbF3 }, + { 0x3E, kbF4 }, { 0x3F, kbF5 }, { 0x40, kbF6 }, + { 0x41, kbF7 }, { 0x42, kbF8 }, { 0x43, kbF9 }, + { 0x44, kbF10 }, { 0x85, kbF11 }, { 0x86, kbF12 }, + + { 0x54, kbF1 }, { 0x55, kbF2 }, { 0x56, kbF3 }, + { 0x57, kbF4 }, { 0x58, kbF5 }, { 0x59, kbF6 }, + { 0x5A, kbF7 }, { 0x5B, kbF8 }, { 0x5C, kbF9 }, + { 0x5D, kbF10 }, { 0x87, kbF11 }, { 0x88, kbF12 }, + + { 0x5E, kbF1 }, { 0x5F, kbF2 }, { 0x60, kbF3 }, + { 0x61, kbF4 }, { 0x62, kbF5 }, { 0x63, kbF6 }, + { 0x64, kbF7 }, { 0x65, kbF8 }, { 0x66, kbF9 }, + { 0x67, kbF10 }, { 0x89, kbF11 }, { 0x8A, kbF12 }, + + { 0x68, kbF1 }, { 0x69, kbF2 }, { 0x6A, kbF3 }, + { 0x6B, kbF4 }, { 0x6C, kbF5 }, { 0x6D, kbF6 }, + { 0x6E, kbF7 }, { 0x6F, kbF8 }, { 0x70, kbF9 }, + { 0x71, kbF10 }, { 0x8B, kbF11 }, { 0x8C, kbF12 }, + + { 0x47, kbHome }, { 0x48, kbUp }, { 0x49, kbPgUp }, + { 0x4B, kbLeft }, { 0x4C, kbCenter}, { 0x4D, kbRight }, + { 0x4F, kbEnd }, { 0x50, kbDown }, { 0x51, kbPgDn }, + { 0x52, kbIns }, { 0x53, kbDel }, + + { 0x77, kbHome }, { 0x8D, kbUp }, { 0x84, kbPgUp }, + { 0x73, kbLeft }, { 0x74, kbRight }, + { 0x75, kbEnd }, { 0x91, kbDown }, { 0x76, kbPgDn }, + { 0x92, kbIns }, { 0x93, kbDel }, + + { 0x97, kbHome | kfGray }, { 0x98, kbUp | kfGray }, { 0x99, kbPgUp | kfGray }, + { 0x9B, kbLeft | kfGray }, { 0x9D, kbRight | kfGray }, + { 0x9F, kbEnd | kfGray }, { 0xA0, kbDown | kfGray }, { 0xA1, kbPgDn | kfGray }, + { 0xA2, kbIns | kfGray }, { 0xA3, kbDel | kfGray } +}; + +int ReadKbdEvent(TEvent *Event, int Wait) +{ + struct plKbdInfo ki; + + UBYTE CharCode, ScanCode; + ULONG KeyCode, KeyFlags; + UWORD CharScan, Flags; + static ULONG PrevFlags = 0; + int I; + const int Tcs = (int) (sizeof(TransCharScan)/sizeof(TransCharScan[0])); + const int Ts = (int) (sizeof(TransScan)/sizeof(TransScan[0])); + + Event->What = evNone; + if(! plKbdReadF(&ki)) return 0; // No data-> no read.. + Event->What = evKeyDown; + + CharCode = ki.ki_ascii; + ScanCode = ki.ki_scan; + CharScan = (UWORD)((((UWORD)ScanCode) << 8) | ((UWORD)CharCode)); + Flags = ki.ki_flags; + KeyCode = 0; + KeyFlags = 0; + + /* printf("Key: %X %X %X %X %X \n", (unsigned long) ki.bNlsShift, (unsigned long) ki.fbStatus, (unsigned long) Flags, (unsigned long) CharCode, (unsigned long) ScanCode);*/ + + if ((Flags & PLKF_SHIFT) != 0) KeyFlags |= kfShift; + if ((Flags & PLKF_CTRL) != 0) KeyFlags |= kfCtrl; + + /* cpCount = sizeof(cpList);*/ + /* rc = DosQueryCp(sizeof(cpList), cpList, &cpCount); // get active code page*/ + if (CharCode != 0) { + // if ((Flags & PLKF_ALT) != 0) KeyFlags |= kfAlt; + } else { + if((Flags & PLKF_ALT) != 0) KeyFlags |= kfAlt; + } + /* if (rc != 0) printf("rc = %d\n", rc);*/ + + if (CharScan == 0) { /* shift/alt/ctrl/caps/scroll/num */ + + } else if (ScanCode == 0) { /* alt numeric */ + KeyCode = CharCode; + KeyFlags |= kfAltXXX; + } else { /* now check special combinations */ + for (I = 0; I < Tcs; I++) + if (TransCharScan[I].CharScan == CharScan) { + KeyCode = TransCharScan[I].KeyCode; + break; + } + if (KeyCode == 0) { + if ((CharCode == 0) || (CharCode == 0xE0)) { + if (CharCode == 0xE0) + KeyFlags |= kfGray; + for (I = 0; I < Ts; I++) + if (TransScan[I].ScanCode == ScanCode) { + KeyCode = TransScan[I].KeyCode; + break; + } + } else { + KeyCode = CharCode; + } + } + } + Event->Key.Code = KeyCode | KeyFlags; + PrevFlags = Flags; + return 1; +} + +#define TM_DIFF(x,y) ((long)(((long)(x) < (long)(y)) ? ((long)(y) - (long)(x)) : ((long)(x) - (long)(y)))) + +int ReadMouseEvent(TEvent *Event, unsigned long EventMask) +{ + static unsigned short PrevState = 0; + static unsigned short PrevButtons = 0; + static TEvent LastMouseEvent = { evNone }; + static ULONG LastEventTime = 0; + static ULONG LastClick = 0; + static ULONG LastClickTime = 0; + static ULONG LastClickCount = 0; +// MOUEVENTINFO mi; + unsigned short Buttons, State, Btn; +// USHORT fWait = MOU_NOWAIT; +// MOUQUEINFO mq; + ULONG CurTime; + UWORD cx, cy; + int butf; + boolean rb, lb; + static int Scx = -1, Scy = -1; + static boolean Slb, Srb; + +// CurTime = plTmGet(); // 2do! + Event->What = evNone; + + //** Distill an event from the current position & button state of the mouse. + MOUSPos(&cx, &cy, &lb, &rb); + cx /= 8; + cy /= 8; + if(Scx == -1) + { + Scx = cx; // Force initial state to here. + Scy = cy; + } + + //** Assume something happened.. Set the mouse' position, + butf = (lb ? 0x01 : 0) | (rb ? 0x02 : 0); + Event->Mouse.X = cx; + Event->Mouse.Y = cy; + Event->Mouse.Count = 1; + + //** 1. Has the buttons state changed? + if(Slb != lb) + { + Event->What = lb ? evMouseDown : evMouseUp; + Event->Mouse.Buttons = 0x01; //lb ? 0x01 : 0; + Slb = lb; + } + else if(Srb != rb) + { + Event->What = rb ? evMouseDown : evMouseUp; + Event->Mouse.Buttons = 0x02; // rb ? 0x02 : 0; + Srb = rb; + } + else if(cx != Scx || cy != Scy) + { + //** Mouse move. + Event->What = evMouseMove; + Event->Mouse.Buttons = butf; + Event->Mouse.Count = 0; + } + + //** Any event? + if(Event->What == evNone) + { + //** Handle repeat here!! + return 0; + } +// printf("[ev=%d, b=%d] ", Event->What, Event->Mouse.Buttons); + + //** Something happened.. + Scx = cx; + Scy = cy; + return 1; +} + + +#if 0 + + + MouGetNumQueEl(&mq, MouseHandle); + if (mq.cEvents == 0) { + if (LastMouseEvent.What == evMouseAuto && (EventMask & evMouseAuto)) { + if (TM_DIFF(CurTime, LastEventTime) >= MouseAutoRepeat) { + *Event = LastMouseEvent; + DosQuerySysInfo(QSV_MS_COUNT, QSV_MS_COUNT, &LastEventTime, 4); + return 1; + } + } + if ((LastMouseEvent.What == evMouseDown || LastMouseEvent.What == evMouseMove) + && + (LastMouseEvent.Mouse.Buttons) + && (EventMask & evMouseAuto)) + { + if (TM_DIFF(CurTime, LastEventTime) >= MouseAutoDelay) { + LastMouseEvent.What = evMouseAuto; + *Event = LastMouseEvent; + DosQuerySysInfo(QSV_MS_COUNT, QSV_MS_COUNT, &LastEventTime, 4); + return 1; + } + } + return 0; + } + + if (MouReadEventQue(&mi, &fWait, MouseHandle) != 0) return 0; + Event->Mouse.X = mi.col; + Event->Mouse.Y = mi.row; + State = mi.fs; + Btn = Buttons = ((State & (2 | 4))?1:0) | + ((State & (8 | 16))?2:0) | + ((State & (32 | 64))?4:0); + if (Buttons != PrevButtons) { + Buttons ^= PrevButtons; + if (PrevButtons & Buttons) + Event->What = evMouseUp; + else + Event->What = evMouseDown; + } else + Event->What = evMouseMove; + Event->Mouse.Buttons = Buttons; + Event->Mouse.Count = 1; + PrevState = State; + PrevButtons = Btn; + + if (Event->What == evMouseDown) { + if (LastClickCount) { + if (LastClick == Event->Mouse.Buttons) { + if (TM_DIFF(CurTime, LastClickTime) <= MouseMultiClick) { + Event->Mouse.Count = ++LastClickCount; + } else { + LastClickCount = 0; + } + } else { + LastClick = 0; + LastClickCount = 0; + LastClickTime = 0; + } + } + + LastClick = Event->Mouse.Buttons; + if (LastClickCount == 0) + LastClickCount = 1; + DosQuerySysInfo(QSV_MS_COUNT, QSV_MS_COUNT, &LastClickTime, 4); + } + /* if (Event->What == evMouseMove) { + LastClick = 0; + LastClickCount = 0; + LastClickTime = 0; + }*/ + { + KBDINFO ki; + USHORT Flags; + TKeyCode KeyFlags = 0; + + ki.cb = sizeof(ki); + KbdGetStatus(&ki, 0); + Flags = ki.fsState; + + if ((Flags & (LEFTSHIFT | RIGHTSHIFT)) != 0) KeyFlags |= kfShift; + if ((Flags & (LEFTCONTROL | RIGHTCONTROL)) != 0) KeyFlags |= kfCtrl; + if ((Flags & (LEFTALT | RIGHTALT)) != 0) KeyFlags |= kfAlt; + + Event->Mouse.KeyMask = KeyFlags; + } + + LastMouseEvent = *Event; + DosQuerySysInfo(QSV_MS_COUNT, QSV_MS_COUNT, &LastEventTime, 4); + return 1; +} + +#endif + +int ConClear() +{ + plScnSetCell(0, 0, plScnWidth(), plScnHeight(), 0x0720); + return 0; +} + +int ConPutBox(int X, int Y, int W, int H, PCell Cell) { + int I; + int MX, MY; + int MouseHidden = 0; + char *p = (char *) Cell; + if (MouseVisible) + ConQueryMousePos(&MX, &MY); + + for (I = 0; I < H; I++) { + if (MouseVisible) + if (Y + I == MY) + if ((MX >= X) && (MX <= X + W)) { + DrawMouse(0); + MouseHidden = 1; + } + plScnWrite(X, Y+I, (UWORD *)p, W); + + if (MouseHidden) { + DrawMouse(1); + MouseHidden = 0; + } + p += W << 1; + } + return 0; +} + +int ConGetBox(int X, int Y, int W, int H, PCell Cell) { + int I; + int MX, MY; + int MouseHidden = 0; +// USHORT WW = (U)(W << 1); + char *p = (char *) Cell; + + if (MouseVisible) + ConQueryMousePos(&MX, &MY); + + for (I = 0; I < H; I++) { + if (MouseVisible) + if (Y + I == MY) + if (MX >= X && MX < X + W) { + DrawMouse(0); + MouseHidden = 1; + } + plScnRead(X, Y+I, (unsigned short*) p, W); + + if (MouseHidden) { + DrawMouse(1); + MouseHidden = 0; + } + p += W << 1; + } + return 0; + +} + +int ConPutLine(int X, int Y, int W, int H, PCell Cell) +{ + int I; + int MX, MY; + int MouseHidden = 0; + char *p = (char *) Cell; + if (MouseVisible) + ConQueryMousePos(&MX, &MY); + + for (I = 0; I < H; I++) { + if (MouseVisible) + if (Y + I == MY) + if (MX >= X && MX < X + W) { + DrawMouse(0); + MouseHidden = 1; + } + plScnWrite(X, Y+I, (UWORD *) p, W); + + if (MouseHidden) { + DrawMouse(1); + MouseHidden = 0; + } + } + return 0; +} + +int ConSetBox(int X, int Y, int W, int H, TCell Cell) { + int I; + int MX, MY; + int MouseHidden = 0; + char *p = (char *) &Cell; + if (MouseVisible) + ConQueryMousePos(&MX, &MY); + + for (I = 0; I < H; I++) { + if (MouseVisible) + if (Y + I == MY) + if (MX >= X && MX < X + W) { + DrawMouse(0); + MouseHidden = 1; + } + plScnSetCell(X, Y+I, W, 1, (UWORD)Cell); + // VioWrtNCell(p, (USHORT)(W), (USHORT)(Y + I), (USHORT)X, 0); + + if (MouseHidden) { + DrawMouse(1); + MouseHidden = 0; + } + } + return 0; +} + +int ConScroll(int Way, int X, int Y, int W, int H, TAttr Fill, int Count) +{ + int MX, MY; + int MouseHidden = 0; + TCell FillCell = (TCell)(Fill << 8); + + if (MousePresent && MouseVisible) + { + ConQueryMousePos(&MX, &MY); + if (MX >= X && MX < X + W && MY >= Y && MY < Y + H) + { + DrawMouse(0); + MouseHidden = 1; + } + } + + switch (Way) + { + case csUp: plScnScrollUp(X, Y, X+W, Y+H, Count, (UWORD)FillCell); break; + case csDown:plScnScrollDown(X, Y, X+W, Y+H, Count, (UWORD)FillCell); break; + case csLeft: +// VioScrollLf((USHORT)Y, (USHORT)X, (USHORT)(Y + H - 1), (USHORT)(X + W - 1), (USHORT)Count, (PBYTE)&FillCell, 0); + break; + case csRight: +// VioScrollRt((USHORT)Y, (USHORT)X, (USHORT)(Y + H - 1), (USHORT)(X + W - 1), (USHORT)Count, (PBYTE)&FillCell, 0); + break; + } + if (MouseHidden) + DrawMouse(1); + return 0; +} + +int ConSetSize(int X, int Y) { + return 0; +} + +int ConQuerySize(int *X, int *Y) { + *X = plScnWidth(); + *Y = plScnHeight(); + return 0; +} + +int ConSetCursorPos(int X, int Y) { + plScnCursorPos(X, Y); + return 0; +} + +int ConQueryCursorPos(int *X, int *Y) { + plScnCursorPosGet(X, Y); + return 0; +} + +int ConShowCursor() { + CursorVisible = 1; + plScnCursorOn(TRUE); + return 0; +} + +int ConHideCursor() { + CursorVisible = 0; + plScnCursorOn(FALSE); + return 0; +} + +int ConSetCursorSize(int Start, int End) { + return 0; +} + +//int ConSetMousePos(int X, int Y) { +// return 0; +//} + + +/****************************************************************************/ +/* */ +/* CODING: Mouse stuff. */ +/* */ +/****************************************************************************/ + + +int ConQueryMousePos(int *X, int *Y) { + UWORD a, b; + boolean lb, rb; + + if(! MOUSIsPresent()) return -1; + + MOUSPos(&a, &b, &lb, &rb); + *X = a / 8; + *Y = b / 8; + return 0; +} + +int ConShowMouse() +{ + MouseVisible = TRUE; + if(! MOUSIsPresent()) return -1; + MOUSCursen(TRUE); + return 0; +} + +int ConHideMouse() +{ + MouseVisible = FALSE; + if(! MOUSIsPresent()) return -1; + MOUSCursen(FALSE); + return 0; +} + +int ConMouseVisible() { + return MouseVisible; +} + +int ConQueryMouseButtons(int *ButtonCount) { + if(ButtonCount != 0) *ButtonCount = 2; + return 0; +} + + + +int ConInit(int XSize, int YSize) +{ + if(Initialized) return 0; + + EventBuf.What = evNone; + MousePresent = MOUSInit(); + ConContinue(); + Initialized = 1; + return 0; +} + +int ConDone() +{ + return ConSuspend(); +} + +int ConSuspend() +{ + plScnSetFlash(TRUE); // Set "flash" mode, not bright mode + ConHideMouse(); +#if defined(SIGBREAK) + signal(SIGBREAK, SIG_DFL); +#endif + signal(SIGINT, SIG_DFL); + return 0; +} + +int ConContinue() +{ +#if defined(SIGBREAK) + signal(SIGBREAK, SIG_IGN); +#endif + signal(SIGINT, SIG_IGN); + plScnSetFlash(FALSE); // Set "bright" mode, not flashing + ConShowMouse(); + return 0; +} + +int GetPipeEvent(TEvent *Event) { +#ifdef DJGPP + int i; + + Event->What = evNone; + for (i = 0; i < MAX_PIPES; i++) { + if (Pipes[i].used == 0) continue; + if (Pipes[i].notify == 0) continue; + if (1) { + //fprintf(stderr, "Pipe New Data: %d\n", i); + Event->What = evNotify; + Event->Msg.View = 0; + Event->Msg.Model = Pipes[i].notify; + Event->Msg.Command = cmPipeRead; + Event->Msg.Param1 = i; + return 1; + } + } +#endif + return 0; +} + +int ConGetEvent(TEventMask EventMask, TEvent *Event, int WaitTime, int Delete) +{ + if (EventBuf.What != evNone) + { + *Event = EventBuf; + if (Delete) EventBuf.What = evNone; + return 0; + } + if (MouseEv.What != evNone) + { + *Event = MouseEv; + if (Delete) MouseEv.What = evNone; + return 0; + } + EventBuf.What = evNone; + Event->What = evNone; + + if(! (ReadKbdEvent(Event, WaitTime) == 1) && (EventMask & evKeyboard)) + { + if(MousePresent && (ReadMouseEvent(Event, EventMask) == 1) && (EventMask & evMouse)) + ; + else + { + if(GetPipeEvent(Event) != 1) + return -1; + } + } + if (Event->What != evNone) + { + if (Event->What == evMouseMove) + { + while (ReadMouseEvent(&MouseEv, EventMask) == 1) + { + if (MouseEv.What == evMouseMove) + { + *Event = MouseEv; + MouseEv.What = evNone; + } + else + break; + } + } + EventBuf = *Event; + if (Delete) EventBuf.What = evNone; + return 0; + } + return -1; +} + + +static PCell SavedScreen = 0; +static int SavedX, SavedY, SaveCursorPosX, SaveCursorPosY; + +int SaveScreen() { + if (SavedScreen) + free(SavedScreen); + + ConQuerySize(&SavedX, &SavedY); + + SavedScreen = (PCell) malloc(SavedX * SavedY * sizeof(PCell)); + + if (SavedScreen) + ConGetBox(0, 0, SavedX, SavedY, SavedScreen); + ConQueryCursorPos(&SaveCursorPosX, &SaveCursorPosY); + return 0; +} + +int RestoreScreen() { + if (SavedScreen) { + ConPutBox(0, 0, SavedX, SavedY, SavedScreen); + ConSetCursorPos(SaveCursorPosX, SaveCursorPosY); + } + return 1; +} + + +GUI::GUI(int &argc, char **argv, int XSize, int YSize) { + fArgc = argc; + fArgv = argv; + ::ConInit(-1, -1); + SaveScreen(); + ::ConSetSize(XSize, YSize); + gui = this; +#ifdef DJGPP + // speed up directory access by turning off unused stat functionality + _djstat_flags |= _STAT_INODE; + _djstat_flags |= _STAT_EXEC_EXT; + _djstat_flags |= _STAT_EXEC_MAGIC; + _djstat_flags |= _STAT_DIRSIZE; + _djstat_flags |= _STAT_ROOT_TIME; + _djstat_flags |= _STAT_WRITEBIT; +#endif +} + +GUI::~GUI() { + RestoreScreen(); + ::ConDone(); + + if(SavedScreen) + { + free(SavedScreen); + SavedScreen = 0; + } + + gui = 0; +} + +int GUI::ConSuspend(void) { + RestoreScreen(); + return ::ConSuspend(); +} + +int GUI::ConContinue(void) { + SaveScreen(); + return ::ConContinue(); +} + +int GUI::ShowEntryScreen() { + TEvent E; + + ConHideMouse(); + RestoreScreen(); + do { gui->ConGetEvent(evKeyDown, &E, -1, 1, 0); } while (E.What != evKeyDown); + ConShowMouse(); + if (frames) + frames->Repaint(); + return 1; +} + +//static int CreatePipeChild(PID &pid, HPIPE &hfPipe, char *Command) { +// return 0; +//} + +static void PipeThread(void *p) { +} + +int GUI::OpenPipe(char *Command, EModel *notify) { +#ifdef DJGPP + int i; + + for (i = 0; i < MAX_PIPES; i++) { + if (Pipes[i].used == 0) { + Pipes[i].id = i; + Pipes[i].notify = notify; + Pipes[i].stopped = 1; + + Pipes[i].fp = xpopen(Command,"r"); + if (Pipes[i].fp == NULL) + return -1; + Pipes[i].used = 1; + //fprintf(stderr, "Pipe Open: %d\n", i); + return i; + } + } + return -1; +#else + return 0; +#endif +} + +int GUI::SetPipeView(int id, EModel *notify) { +#ifdef DJGPP + if (id < 0 || id >= MAX_PIPES) + return -1; + if (Pipes[id].used == 0) + return -1; + //fprintf(stderr, "Pipe View: %d %08X\n", id, notify); + Pipes[id].notify = notify; +#endif + return 0; +} + +int GUI::ReadPipe(int id, void *buffer, int len) { +#ifdef DJGPP + int rc; + if (id < 0 || id >= MAX_PIPES) + return -1; + if (Pipes[id].used == 0) + return -1; + //fprintf(stderr, "Pipe Read: Get %d %d\n", id, len); + + rc = fread(buffer,1,len,Pipes[id].fp); + //fprintf(stderr, "Pipe Read: Got %d %d\n", id, rc); + if (ferror(Pipes[id].fp)) { + Pipes[id].stopped = 1; + return 0; + } + return rc == 0 ? -1 : rc; +#else + return 0; +#endif +} + +int GUI::ClosePipe(int id) { +#ifdef DJGPP + if (id < 0 || id >= MAX_PIPES) + return -1; + if (Pipes[id].used == 0) + return -1; + Pipes[id].used = 0; + //fprintf(stderr, "Pipe Close: %d\n", id); + return xpclose(Pipes[id].fp); +#else + return 0; +#endif +} + +int GUI::RunProgram(int mode, char *Command) { + int rc, W, H, W1, H1; + + ConQuerySize(&W, &H); + ConHideMouse(); + ConSuspend(); + + if (*Command == 0) // empty string = shell + Command = getenv( + "COMSPEC" + ); + + rc = system(Command); + + ConContinue(); + ConShowMouse(); + ConQuerySize(&W1, &H1); + + if (W != W1 || H != H1) { + frames->Resize(W1, H1); + } + frames->Repaint(); + return rc; +} + +int ConSetTitle(char *Title, char *STitle) { + return 0; +} + +int ConGetTitle(char *Title, int MaxLen, char *STitle, int SMaxLen) { + strcpy(Title, "FTE"); + strcpy(STitle, "FTE"); + return 0; +} + +int ConCursorVisible() { + return 0; +} + +int ConPutEvent(TEvent Event) +{ + EventBuf = Event; + return 0; +} + +char ConGetDrawChar(int index) { + // static char tab[] = "Ú¿ÀÙijÂôÁÅ\x1Aúı°"; + static const char tab[] = "Ú¿ÀÙijÂôÁÅ\x1Aú\x04Ä\x18\x19±°\x1B\x1A"; + + assert(strlen(tab) > 20); + assert(index >= 0); + + assert(index >= 0 && index < (int)strlen(tab)); + + return tab[index]; +} diff --git a/src/con_i18n.cpp b/src/con_i18n.cpp new file mode 100644 index 0000000..548cfe8 --- /dev/null +++ b/src/con_i18n.cpp @@ -0,0 +1,397 @@ +/* + * con_i18n.cpp + * + * Copyright (c) 1998, Zdenek Kabelac + * + * I18N support by kabi@fi.muni.cz + * + * written as plain 'C' module and might be used + * in other programs to implement I18N support + */ + + +#include +#include +#include +#include +#include +#include +#include + +#include "con_i18n.h" + +#define KEYMASK 0xff +#define KEYBYTEMAX 0xf00 + +#ifdef USE_HARD_REMAP +/* + * This part is used when your Xserver doesn't work well with XKB extension + */ + + +/* Keyboard definition file - currently only Czech national keyboard + * write your own keyboard for your language + * And remember - this is supposed to be used only if your Xserver + * is not supporting keyboard extension + */ +#include "con_ikcz.h" + +/* + * Quite a complex function to convert normal keys + * to dead-keys and remapped keys + */ +static int I18NKeyAnalyze(XKeyEvent * keyEvent, KeySym * key, /*fold00*/ + char *keyName, int nbytes) +{ + static long prev_state = 0, local_switch = 0, + keypos = 0, last_keypos = 0, remap = 0; + long i; + struct keyboardRec *kbdActual; + + /* Find the state of keyboard + * Check for different ISO group or modifier 5 + * So to activate remaping, you need to press at least + * ScrollLock which is usually mapped as modifier 5 + */ + i = ((keyEvent->state | local_switch) & 0xFFA0); + + if (i != prev_state) { + /* reset table position */ + last_keypos = keypos = 0; + prev_state = i; + } + + if (keyEvent->type == KeyPress) { + if (i && ((*key == XK_Pause) || (*key == XK_F21))) { + remap = !remap; + return 0; + } else if (*key == XK_F23) { + local_switch ^= (1UL<< 12); + return 0; + } + } + /* + * Check for already remapped ISO8859-X keys + * this should not normaly happen :-) + * as we need to use this hack + */ + + if ((*key > KEYMASK) && (*key < KEYBYTEMAX) || (*key > 0xffffff00)) { + *key &= KEYMASK; + keyName[0] = (char) *key; + return 1; + } + /* Select keyboard map */ + if (!i) + kbdActual = nationalKey[0]; + else if (!remap) + kbdActual = nationalKey[1]; + else + kbdActual = nationalKey[2]; + + if (keyEvent->type == KeyPress) { + long i = last_keypos; + + /* + * Search for DeadKey -> do loop over all tables. + * + * Note: We can define ONE DeadKey and use + * it for several tables sequentially + */ + for (;;) { + i++; + if ((kbdActual[0].tab == NULL) || kbdActual[i].tab == NULL) { + i = 0; + if (kbdActual[i].tab == NULL) { + /* Looks like empty table -> IGNORE */ + keypos = i; + return nbytes; + } + } + if (i == last_keypos) + break; + + if (kbdActual[i].deadkey == *key) { + keypos = kbdActual[i].next; + /* Found DeadKey -> delete it + * and mark actual position for next search */ + last_keypos = i; + keyName[0] = *key = 0; + return 0; + } + } + } else if (keypos) + return 0; /* ignore key release */ + + /* Now we know it is not a DeadKey and we + * are in selected remaping keyboard table */ + + /* printf("** key:%5d\tstatus:0x%x\n", *key, prev_state); */ + if (*key < KEYBYTEMAX) { + /* + * this is selected constant and will change when + * this editor will be able to write in japan :-) + */ + int i = 0; + + /* remaping only real keys */ + while (kbdActual[keypos].tab[i].key_english != 0) { + if (*key == kbdActual[keypos].tab[i].key_english) { + *key = kbdActual[keypos].tab[i].key_remap; + break; + } + i++; + } + last_keypos = keypos = kbdActual[keypos].next; + /* printf("** remap: %3d %3d\n", keypos, *key); */ + keyName[0] = *key && KEYMASK; + return 1; + } + return 0; +} + /*FOLD00*/ +#else + +/********************************************* + * * + * Standart methods for reading Keyboard * + * * + *********************************************/ + +/* ISO-8859-2 key-change + + * All these functions are for keyboard reading. + * Correct displaing of this text is another thing, + * but as I only need ISO-8859 encoding support, + * I don't care about this (for now). + */ +static int I18NKeyAnalyze(XKeyEvent * keyEvent, KeySym * key, /*fold00*/ + char *keyName, int nbytes) +{ + KeySym t = (unsigned char) keyName[0]; + + /* + * ISO-8859-2 is using some characters from 8859-1 and + * rest of them is located between 0x100 - 0x200 in 'X' so + * with ISO-8859-2 font we'll remap them down bellow < 0x100 + * This is mostly true for all Latin-X alphas, just + * special font to display them correctly is needed. + * This jobs does Xserver - and keysymbol is returned + * in the 1st. byte of keyName string. + */ + if ((nbytes == 1) && *key < KEYBYTEMAX) + *key = t; +#ifdef USE_HACK_FOR_BAD_XSERVER + /* + * this is really hack - but some Xservers are somewhat + * strange, so we remap character manually + */ + else if (!nbytes && (*key > KEYMASK) && (*key < KEYBYTEMAX)) { + *key &= KEYMASK; + keyName[0] = *key & KEYMASK; + nbytes = 1; + } +#endif + return nbytes; +} + /*FOLD00*/ +#endif + +/* + * Initialize I18N functions - took me hours to + * figure out how this works even though it was + * cut & pasted from 'xterm' sources, but as 'xterm' + * is using Xt Toolkit some things have to be made + * different + */ +XIC I18NInit(Display * display, Window win, unsigned long *mask) /*fold00*/ +{ + XIC xic = (XIC) NULL; +#if XlibSpecificationRelease >= 6 + XIM xim = (XIM) NULL; + XIMStyles *xim_styles; + XIMStyle input_style = 0; + char *s, tmp[256]; + int found = False; + + *mask = 0; + + /* Locale setting taken from XtSetLanguageProc */ + if (!(s = setlocale(LC_ALL, ""))) + fprintf(stderr, "I18N warning: Locale not supported by C library, " + "locale unchanged!\n"); + + if (!XSupportsLocale()) { + fprintf(stderr, "I18N warning: Locale not supported by Xlib, " + "locale set to C!\n"); + s = setlocale(LC_ALL, "C"); + } + if (!XSetLocaleModifiers("")) + fprintf(stderr, "I18N warning: X locale modifiers not supported, " + "using default\n"); + + xim = XOpenIM(display, NULL, NULL, NULL); + if (xim == NULL) { + // there are languages without Input Methods ???? + fprintf(stderr, "I18N warning: Input method not specified\n"); + return NULL; + } + + if (XGetIMValues(xim, XNQueryInputStyle, &xim_styles, NULL) + || xim_styles == NULL) { + fprintf(stderr, "I18N error: Input method doesn't support any style\n"); + XCloseIM(xim); + return NULL; + } + + /* + * This is some kind of debugging message to inform user + * that something is wrong with his system + */ + if (s != NULL && (strstr(s, XLocaleOfIM(xim)) == NULL)) + fprintf(stderr, "I18N warning: System locale: \"%s\" differs from " + "IM locale: \"%s\"...\n", s, XLocaleOfIM(xim)); + + /* + * This part is cut&paste from other sources + * There is no reason to do it this way, because + * the only input style currently supported is Root + * but for the future extension I'll leave it here + */ + + strcpy(tmp, XIM_INPUT_STYLE); + for (s = tmp; s && !found;) { + char *ns, *end; + int i; + + while ((*s != 0) && isspace(*s)) + s++; + + if (*s == 0) + break; + + if ((ns = end = strchr(s, ',')) != 0) + ns++; + else + end = s + strlen(s); + + while (isspace(*end)) + end--; + *end = '\0'; + + if (!strcmp(s, "OverTheSpot")) + input_style = (XIMPreeditPosition | XIMStatusArea); + else if (!strcmp(s, "OffTheSpot")) + input_style = (XIMPreeditArea | XIMStatusArea); + else if (!strcmp(s, "Root")) + input_style = (XIMPreeditNothing | XIMStatusNothing); + + for (i = 0; (unsigned short) i < xim_styles->count_styles; i++) + if (input_style == xim_styles->supported_styles[i]) { + found = True; + break; + } + s = ns; + } + XFree(xim_styles); + + if (!found) { + fprintf(stderr, "I18N error: Input method doesn't support my " + "preedit type\n"); + XCloseIM(xim); + return NULL; + } + /* This program only understand the Root preedit_style yet */ + if (input_style != (XIMPreeditNothing | XIMStatusNothing)) { + fprintf(stderr, "I18N error: This program only supports the " + "'Root' preedit type\n"); + XCloseIM(xim); + return NULL; + } + xic = XCreateIC(xim, XNInputStyle, input_style, + XNClientWindow, win, + XNFocusWindow, win, + NULL); + if (xic == NULL) { + fprintf(stderr, "I18N error: Failed to create input context\n"); + XCloseIM(xim); + } else if (XGetICValues(xic, XNFilterEvents, mask, NULL)) + fprintf(stderr, "I18N error: Can't get Event Mask\n"); +#else + *mask = 0; +#endif + return xic; +} + /*FOLD00*/ + +void I18NFocusIn(XIC xic) /*fold00*/ +{ +#if XlibSpecificationRelease >= 6 + if (xic != NULL) + XSetICFocus(xic); +#endif +} + /*FOLD00*/ + +void I18NFocusOut(XIC xic) /*fold00*/ +{ +#if XlibSpecificationRelease >= 6 + if (xic != NULL) + XUnsetICFocus(xic); +#endif +} + /*FOLD00*/ + +/* + * Lookup correct keysymbol from keymap event + */ +int I18NLookupString(XKeyEvent * keyEvent, char *keyName, int keySize, /*FOLD00*/ + KeySym * key, XIC xic) +{ + static int showKeys = 0; + int nbytes = 0; + +#if XlibSpecificationRelease >= 6 + if (xic != NULL) { + if (keyEvent->type == KeyPress) { + Status status_return; + + /* No KeyRelease events here ! */ +#if 1 + nbytes = XmbLookupString(xic, keyEvent, keyName, keySize, + key, &status_return); +#else + wchar_t wk; + nbytes = XwcLookupString(xic, keyEvent, &wk, 1, key, &status_return); + printf("code=%0X\n", wk); + keySize = 1; + keyName[0] = wk & 0xFF; +#endif + } + } else +#endif + do { + static XComposeStatus compose_status = { NULL, 0 }; + nbytes = XLookupString(keyEvent, keyName, keySize, + key, &compose_status); + } while (0); + + + if (showKeys) { + fprintf(stderr, "Key: 0x%04lx '%s'\tKeyEventState:0x%x\t", + *key, XKeysymToString(*key), keyEvent->state); + if (nbytes && isprint(keyName[0])) { + keyName[nbytes] = 0; + fprintf(stderr, "String:'%s' Size:%2d ", keyName, nbytes); + } + fputs("\n", stderr); + } + if (((*key == XK_F1) || (*key == XK_F11)) + && ((keyEvent->state & (ShiftMask | ControlMask)) + == (ShiftMask | ControlMask)) + && (keyEvent->type == KeyPress)) + showKeys = !showKeys; + + return I18NKeyAnalyze(keyEvent, key, keyName, nbytes); +} + /*FOLD00*/ diff --git a/src/con_i18n.h b/src/con_i18n.h new file mode 100644 index 0000000..cde3c2c --- /dev/null +++ b/src/con_i18n.h @@ -0,0 +1,32 @@ +#ifndef __CONI18N_H__ +#define __CONI18N_H__ + +#include +#include + +/* + * For now the only supported input style is root !!! + * in future this should be read from resources + */ +#define XIM_INPUT_STYLE "Root" + +struct remapKey { + KeySym key_english; + KeySym key_remap; +}; + +struct keyboardRec { + struct remapKey *tab; + KeySym deadkey; + short next; +}; + +/* + * prototypes for I18N functions + */ +extern void I18NFocusOut(XIC); +extern void I18NFocusIn(XIC); +extern int I18NLookupString(XKeyEvent *, char *, int, KeySym *, XIC); +extern XIC I18NInit(Display *, Window, unsigned long *); + +#endif diff --git a/src/con_ikcz.h b/src/con_ikcz.h new file mode 100644 index 0000000..a6964c9 --- /dev/null +++ b/src/con_ikcz.h @@ -0,0 +1,390 @@ +#ifndef __CON_IKCS_H +#define __CON_IKCS_H + +static struct remapKey keyboardStd[] = +{ + {0,} +}; + +static struct remapKey keyboardHalfCz[] = +{ + {XK_2, 0xff & 'ì'}, + {XK_3, 0xff & '¹'}, + {XK_4, 0xff & 'è'}, + {XK_5, 0xff & 'ø'}, + {XK_6, 0xff & '¾'}, + {XK_7, 0xff & 'ý'}, + {XK_8, 0xff & 'á'}, + {XK_9, 0xff & 'í'}, + {XK_0, 0xff & 'é'}, + {0,} +}; + +static struct remapKey keyboardFullCz[] = +{ + {XK_1, 0xff & '+'}, + {XK_exclam, XK_1}, + {XK_2, 0xff & 'ì'}, + {XK_at, XK_2}, + {XK_3, 0xff & '¹'}, + {XK_numbersign, XK_3}, + {XK_4, 0xff & 'è'}, + {XK_dollar, XK_4}, + {XK_5, 0xff & 'ø'}, + {XK_percent, XK_5}, + {XK_6, 0xff & '¾'}, + {XK_asciicircum, XK_6}, + {XK_7, 0xff & 'ý'}, + {XK_ampersand, XK_7}, + {XK_8, 0xff & 'á'}, + {XK_asterisk, XK_8}, + {XK_9, 0xff & 'í'}, + {XK_parenleft, XK_9}, + {XK_0, 0xff & 'é'}, + {XK_parenright, XK_0}, + + {XK_minus, XK_equal}, + {XK_underscore, XK_percent}, + + {XK_bracketleft, 0xff & 'ú'}, + {XK_braceleft, 0xff & '/'}, + {XK_bracketright, 0xff & ')'}, + {XK_braceright, 0xff & '('}, + + {XK_semicolon, 0xff & 'ù'}, + {XK_apostrophe, 0xff & '§'}, + {XK_colon, 0xff & '"'}, + {XK_quotedbl, 0xff & '!'}, + + {XK_comma, 0xff & ','}, + {XK_less, 0xff & '?'}, + {XK_period, 0xff & '.'}, + {XK_greater, 0xff & ':'}, + {XK_question, 0xff & '_'}, + {XK_slash, 0xff & '-'}, + + {0,} +}; + +static struct remapKey keyboardAcute[] = +{ + {XK_w, 0xff & 'ì'}, + {XK_W, 0xff & 'Ì'}, + {XK_e, 0xff & 'é'}, + {XK_E, 0xff & 'É'}, + {XK_r, 0xff & 'à'}, + {XK_R, 0xff & 'À'}, + {XK_t, 0xff & '»'}, + {XK_T, 0xff & '«'}, + {XK_y, 0xff & 'ý'}, + {XK_Y, 0xff & 'Ý'}, + {XK_u, 0xff & 'ú'}, + {XK_U, 0xff & 'Ú'}, + {XK_i, 0xff & 'í'}, + {XK_I, 0xff & 'Í'}, + {XK_o, 0xff & 'ó'}, + {XK_O, 0xff & 'Ó'}, + {XK_p, 0xff & '§'}, + {XK_P, 0xff & '§'}, + + {XK_a, 0xff & 'á'}, + {XK_A, 0xff & 'Á'}, + {XK_s, 0xff & '¶'}, + {XK_S, 0xff & '¦'}, + {XK_d, 0xff & 'ï'}, + {XK_D, 0xff & 'Ï'}, + {XK_h, 0xff & 'þ'}, + {XK_H, 0xff & 'Þ'}, + {XK_l, 0xff & 'å'}, + {XK_L, 0xff & 'Å'}, + + {XK_z, 0xff & '¼'}, + {XK_Z, 0xff & '¬'}, + {XK_x, 0xff & '×'}, + {XK_X, 0xff & '×'}, + {XK_c, 0xff & 'æ'}, + {XK_C, 0xff & 'Æ'}, + {XK_b, 0xff & 'ß'}, + {XK_B, 0xff & 'ß'}, + {XK_n, 0xff & 'ñ'}, + {XK_N, 0xff & 'Ñ'}, + + {XK_equal, 0xff & '´'}, + + {0,} +}; + +static struct remapKey keyboardCaron[] = +{ + {XK_e, 0xff & 'ì'}, + {XK_E, 0xff & 'Ì'}, + {XK_r, 0xff & 'ø'}, + {XK_R, 0xff & 'Ø'}, + {XK_t, 0xff & '»'}, + {XK_T, 0xff & '«'}, + {XK_u, 0xff & 'ù'}, + {XK_U, 0xff & 'Ù'}, + {XK_i, 0xff & 'î'}, + {XK_I, 0xff & 'Î'}, + {XK_o, 0xff & 'ö'}, + {XK_O, 0xff & 'Ö'}, + + {XK_a, 0xff & 'ä'}, + {XK_A, 0xff & 'Ä'}, + {XK_s, 0xff & '¹'}, + {XK_S, 0xff & '©'}, + {XK_d, 0xff & 'ï'}, + {XK_D, 0xff & 'Ï'}, + {XK_l, 0xff & 'µ'}, + {XK_L, 0xff & '¥'}, + + {XK_z, 0xff & '¾'}, + {XK_Z, 0xff & '®'}, + {XK_x, 0xff & '¤'}, + {XK_X, 0xff & '¤'}, + {XK_c, 0xff & 'è'}, + {XK_C, 0xff & 'È'}, + {XK_n, 0xff & 'ò'}, + {XK_N, 0xff & 'Ò'}, + + {XK_plus, 0xff & '·'}, + {0,} +}; + +static struct remapKey keyboardFirst[] = +{ + {XK_w, 0xff & 'ì'}, + {XK_W, 0xff & 'Ì'}, + {XK_e, 0xff & 'é'}, + {XK_E, 0xff & 'É'}, + {XK_r, 0xff & 'ø'}, + {XK_R, 0xff & 'Ø'}, + {XK_t, 0xff & '»'}, + {XK_T, 0xff & '«'}, + {XK_y, 0xff & 'ý'}, + {XK_Y, 0xff & 'Ý'}, + {XK_u, 0xff & 'ú'}, + {XK_U, 0xff & 'Ú'}, + {XK_i, 0xff & 'í'}, + {XK_I, 0xff & 'Í'}, + {XK_o, 0xff & 'ó'}, + {XK_O, 0xff & 'Ó'}, + {XK_p, 0xff & '§'}, + {XK_P, 0xff & '§'}, + + {XK_a, 0xff & 'á'}, + {XK_A, 0xff & 'Á'}, + {XK_s, 0xff & '¹'}, + {XK_S, 0xff & '©'}, + {XK_d, 0xff & 'ï'}, + {XK_D, 0xff & 'Ï'}, + {XK_h, 0xff & 'þ'}, + {XK_H, 0xff & 'Þ'}, + {XK_l, 0xff & 'å'}, + {XK_L, 0xff & 'Å'}, + + {XK_z, 0xff & '¾'}, + {XK_Z, 0xff & '®'}, + {XK_x, 0xff & '×'}, + {XK_X, 0xff & '×'}, + {XK_c, 0xff & 'è'}, + {XK_C, 0xff & 'È'}, + {XK_b, 0xff & 'ß'}, + {XK_B, 0xff & 'ß'}, + {XK_n, 0xff & 'ò'}, + {XK_N, 0xff & 'Ò'}, + + {0,} +}; + +static struct remapKey keyboardSecond[] = +{ + {XK_equal, 0xff & '´'}, + {XK_plus, 0xff & '·'}, + + {XK_e, 0xff & 'ì'}, + {XK_E, 0xff & 'Ì'}, + {XK_r, 0xff & 'à'}, + {XK_R, 0xff & 'À'}, + {XK_t, 0xff & 'þ'}, + {XK_T, 0xff & 'Þ'}, + {XK_u, 0xff & 'ù'}, + {XK_U, 0xff & 'Ù'}, + {XK_i, 0xff & 'î'}, + {XK_I, 0xff & 'Î'}, + {XK_o, 0xff & 'ö'}, + {XK_O, 0xff & 'Ö'}, + + {XK_a, 0xff & 'ä'}, + {XK_A, 0xff & 'Ä'}, + {XK_s, 0xff & '¶'}, + {XK_S, 0xff & '¦'}, + {XK_d, 0xff & 'ð'}, + {XK_D, 0xff & 'Ð'}, + {XK_l, 0xff & 'µ'}, + {XK_L, 0xff & '¥'}, + + {XK_z, 0xff & '¼'}, + {XK_Z, 0xff & '¬'}, + {XK_x, 0xff & '¤'}, + {XK_X, 0xff & '¤'}, + {XK_c, 0xff & 'æ'}, + {XK_C, 0xff & 'Æ'}, + {XK_n, 0xff & 'ñ'}, + {XK_N, 0xff & 'Ñ'}, + + {0,} +}; + + + +static struct remapKey keyboardThird[] = +{ + {XK_a, 0xff & 'â'}, + {XK_A, 0xff & 'Â'}, + {XK_e, 0xff & 'ë'}, + {XK_E, 0xff & 'Ë'}, + {XK_u, 0xff & 'ü'}, + {XK_U, 0xff & 'Ü'}, + {XK_o, 0xff & 'ô'}, + {XK_O, 0xff & 'Ô'}, + + {XK_s, 0xff & 'ß'}, + {XK_S, 0xff & 'ß'}, + {XK_l, 0xff & '³'}, + {XK_L, 0xff & '£'}, + + {XK_z, 0xff & '¿'}, + {XK_Z, 0xff & '¯'}, + {XK_c, 0xff & 'ç'}, + {XK_C, 0xff & 'Ç'}, + + {0,} +}; + +static struct remapKey keyboardFourth[] = +{ + {XK_a, 0xff & 'ã'}, + {XK_A, 0xff & 'Ã'}, + {XK_e, 0xff & 'ê'}, + {XK_E, 0xff & 'Ê'}, + {XK_u, 0xff & 'û'}, + {XK_U, 0xff & 'Ü'}, + {XK_o, 0xff & 'õ'}, + {XK_O, 0xff & 'Õ'}, + + {XK_l, 0xff & '£'}, + {XK_L, 0xff & '£'}, + + {0,} +}; + +static struct remapKey keyboardFifth[] = +{ + {XK_a, 0xff & '±'}, + {XK_A, 0xff & '¡'}, + {XK_o, 0xff & '§'}, + {XK_O, 0xff & '§'}, + + {XK_l, 0xff & '|'}, + {XK_L, 0xff & '|'}, + + {0,} +}; + +#define KEYMAPS_MACRO \ + {keyboardAcute, 0, 0}, /* 1 */ \ + {keyboardCaron, 0, 0}, /* 2 */ \ + {keyboardFirst, 0, 0}, /* 3 */ \ + {keyboardSecond, 0, 0}, /* 4 */ \ + {keyboardThird, 0, 0}, /* 5 */ \ + {keyboardFourth, 0, 0}, /* 6 */ \ + {keyboardFifth, 0, 0}, /* 7 */ + +#ifdef XK_dead_acute +#define XKB_DEAD_KEYS \ + {keyboardStd, XK_dead_acute, 1}, \ + {keyboardStd, XK_dead_caron, 2}, \ + {keyboardStd, XK_dead_iota, 3}, \ + {keyboardStd, XK_dead_iota, 4}, \ + {keyboardStd, XK_dead_iota, 5}, \ + {keyboardStd, XK_dead_iota, 6}, \ + {keyboardStd, XK_dead_iota, 7}, \ + {keyboardStd, XK_dead_iota, 0}, + +#else +#define XKB_DEAD_KEYS +#endif + +#ifdef XK_F22 +#define F22_DEAD_KEYS \ + {keyboardStd, XK_F22, 3}, \ + {keyboardStd, XK_F22, 4}, \ + {keyboardStd, XK_F22, 5}, \ + {keyboardStd, XK_F22, 6}, \ + {keyboardStd, XK_F22, 7}, \ + {keyboardStd, XK_F22, 0}, +#else +#define F22_DEAD_KEYS +#endif + +#define KBD_MACRO \ + {keyboardStd, XK_Print, 3}, \ + {keyboardStd, XK_Print, 4}, \ + {keyboardStd, XK_Print, 5}, \ + {keyboardStd, XK_Print, 6}, \ + {keyboardStd, XK_Print, 7}, \ + {keyboardStd, XK_Print, 0}, \ + XKB_DEAD_KEYS \ + F22_DEAD_KEYS + + +static struct keyboardRec kbdStdRec[] = +{ + {keyboardStd, 0, 0}, /* 0 */ + + KEYMAPS_MACRO + + KBD_MACRO + + {NULL,} +}; + +static struct keyboardRec kbdHalfCzRec[] = +{ + {keyboardHalfCz, 0, 0}, /* 0 */ + + KEYMAPS_MACRO + + KBD_MACRO + + {NULL,} +}; + +static struct keyboardRec kbdFullCzRec[] = +{ + {keyboardFullCz, 0, 0}, /* 0 */ + + KEYMAPS_MACRO + + {keyboardStd, XK_equal, 1}, + {keyboardStd, XK_plus, 2}, + + KBD_MACRO + + {NULL,} +}; + +/* + * one standart keyboard and two national keyboards + * (for programmers and for writers) + */ +static struct keyboardRec *nationalKey[] = +{ + kbdStdRec, + kbdHalfCzRec, + kbdFullCzRec, + 0 +}; + +#endif diff --git a/src/con_linux.cpp b/src/con_linux.cpp new file mode 100644 index 0000000..aded0eb --- /dev/null +++ b/src/con_linux.cpp @@ -0,0 +1,1205 @@ +/* con_linux.cpp + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +// If you're searching for portability it is not here ;-) + +#define USE_GPM //uncomment here to use GPM +#define USE_SCRNMAP // use USER translation table instead of direct mapping + // The translation table is assumed to be invertible (more or less). + // How do we get other translation tables from kernel, the USER one + // is null mapping by default (not very useful)? + +// PROBLEM: we use raw mode, and this disables the console +// switching (consoles cannot be switched when the editor is busy). +// probably needs to be fixed in the kernel (IMO kernel should +// switch consoles when raw mode is used, unless console is under +// VT_PROCESS control). Why does kernel trust user processes to do it? + +// FIX: caps lock is ignored (I haven't pressed it in years, except by mistake). +// FIX: access GPM clipboard. how? + +// ... some more comments below + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef USE_GPM +extern "C" { +#include +} +#endif + +#include "console.h" +#include "gui.h" + +#define MAX_PIPES 4 +//#define PIPE_BUFLEN 4096 + +typedef struct { + int used; + int id; + int fd; + int pid; + int stopped; + EModel *notify; +} GPipe; + +static GPipe Pipes[MAX_PIPES] = { + { 0 }, { 0 }, { 0 }, { 0 } +}; + +#define die(s) { printf("%s\n", s); exit(1); } while(0); + +unsigned int VideoCols = 80; +unsigned int VideoRows = 25; +unsigned int CursorX = 0; +unsigned int CursorY = 0; +int CursorVisible = 1; +int VtNum = -1; +static int VtFd = -1; +static int VcsFd = -1; +struct termios Save_termios; +struct kbdiacrs diacr_table; +#ifdef USE_GPM +int GpmFd = -1; +#endif +int LastMouseX = 0, LastMouseY = 0; +int WindowChanged = 0; +int drawPointer = 1; +int mouseDrawn = 0; +TCell MousePosCell; +#ifdef USE_SCRNMAP +static int noCharTrans = 0; + +static unsigned char toScreen[256]; +static unsigned char fromScreen[256]; +#endif + +#define MEM_PAGE_SIZE 4096 +#define VIDEO_SIZE (VideoCols * VideoRows * 2) +#define VIDEO_MAP_SIZE ((VIDEO_SIZE | (MEM_PAGE_SIZE - 1)) + 1) + +int GetKeyEvent(TEvent *Event); +int GetMouseEvent(TEvent *Event); + +void mouseShow() { +#ifdef USE_GPM + if (GpmFd != -1 && VcsFd != -1 && drawPointer && mouseDrawn == 0) { + int pos = (LastMouseX + LastMouseY * VideoCols) * 2 + 4; + lseek(VcsFd, pos, SEEK_SET); + read(VcsFd, &MousePosCell, 2); + TCell newCell = MousePosCell ^ 0x7700; // correct ? + lseek(VcsFd, pos, SEEK_SET); + write(VcsFd, &newCell, 2); + mouseDrawn = 1; + } +#endif +} + +void mouseHide() { +#ifdef USE_GPM + if (GpmFd != -1 && VcsFd != -1 && drawPointer && mouseDrawn == 1) { + int pos = (LastMouseX + LastMouseY * VideoCols) * 2 + 4; + lseek(VcsFd, pos, SEEK_SET); + write(VcsFd, &MousePosCell, 2); + mouseDrawn = 0; + } +#endif +} + +void SigWindowChanged(int arg) { + signal(SIGWINCH, SigWindowChanged); + WindowChanged = 1; +} + +static void Cleanup() { + ConDone(); +} + +static void Die(int) { + ConDone(); + exit(66); +} + +int ConInit(int XSize, int YSize) { + int tmp; + int mode; + struct termios newt; + //char ttyname[20]; + char vcsname[20]; +// struct vt_mode vtm; + //long free_tty; +// struct winsize ws; + struct stat stb; + unsigned char vc_data[4]; +#ifdef USE_GPM + Gpm_Connect conn; +#endif + + VtFd = 2; /* try stderr as output */ + if (isatty(VtFd) == 0) { + die("not a terminal."); + } + if (fstat(VtFd, &stb) != 0) { + perror("stat"); + die("stat failed"); + } + VtNum = MINOR(stb.st_rdev); + if (MAJOR(stb.st_rdev) != TTY_MAJOR) + die("Not running in a virtual console."); + if (ioctl(VtFd, KDGKBMODE, &mode) != 0) + die("failed to get kbdmode"); +#if 0 + if (mode != K_XLATE) { // X, etc... + sprintf(ttyname, "/dev/console"); + if ((VtFd = open(ttyname, O_RDWR)) == -1) + die("failed to open /dev/console"); + if (ioctl(VtFd, VT_OPENQRY, &free_tty) < 0 || free_tty == -1) + die("could not find a free tty\n"); + close(VtFd); + VtNum = free_tty; + sprintf(ttyname, "/dev/tty%d", VtNum); + if ((VtFd = open(ttyname, O_RDWR)) == -1) + die("could not open tty"); + } +#endif + sprintf(vcsname, "/dev/vcsa%d", VtNum); + + /* + * This is the _only_ place that we use our extra privs if any, + * If there is an error, we drop them prior to calling recovery + * functions, if we succeed we go back as well. + * + * Ben Collins + */ + extern uid_t effuid; + extern gid_t effgid; + + seteuid(effuid); + setegid(effgid); + VcsFd = open(vcsname, O_RDWR); + setuid(getuid()); + setgid(getgid()); + + if (VcsFd == -1) { + perror("open"); + die("failed to open /dev/vcsa*"); + } + if (read(VcsFd, &vc_data, 4) != 4) { + perror("read"); + die("failed to read from /dev/vcsa*"); + } + VideoRows = vc_data[0]; + VideoCols = vc_data[1]; + CursorX = vc_data[2]; + CursorY = vc_data[3]; + +#ifdef USE_SCRNMAP + if (ioctl(VtFd, GIO_SCRNMAP, &toScreen) == -1) + die("could not get screen character mapping!"); + + { + int c; + for (c = 0; c < 256; c++) + fromScreen[c] = 0; + for (c = 0; c < 256; c++) + fromScreen[toScreen[c]] = c; + } +#endif + + tmp = tcgetattr(VtFd, &Save_termios); + if (tmp) fprintf(stderr, "tcsetattr = %d\n", tmp); + tmp = tcgetattr(VtFd, &newt); + if (tmp) fprintf(stderr, "tcsetattr = %d\n", tmp); + + newt.c_lflag &= ~ (ICANON | ECHO | ISIG); + newt.c_iflag = 0; + newt.c_cc[VMIN] = 16; + newt.c_cc[VTIME] = 1; + tmp = tcsetattr(VtFd, TCSAFLUSH, &newt); + if (tmp) fprintf(stderr, "tcsetattr = %d\n", tmp); + + /* set keyboard to return MEDIUMRAW mode */ + if (ioctl(VtFd, KDSKBMODE, K_MEDIUMRAW) != 0) { + perror("Could not activate K_MEDIUMRAW mode"); + tmp = tcsetattr(VtFd, 0, &Save_termios); + die("could not activate medium raw mode\n"); + } + + /* get keyboard diacritics table */ + if (ioctl(VtFd, KDGKBDIACR, &diacr_table) != 0) { + perror("Could not get diacritics table"); + diacr_table.kb_cnt=0; + } + + signal(SIGWINCH, SigWindowChanged); + signal(SIGSEGV, Die); + signal(SIGBUS, Die); + signal(SIGIOT, Die); + signal(SIGQUIT, Die); + signal(SIGTERM, Die); + signal(SIGPIPE, SIG_IGN); + signal(SIGALRM, SIG_IGN); + signal(SIGHUP, Die); + atexit(Cleanup); + +#ifdef USE_GPM + conn.eventMask = (unsigned short)~0U; + conn.defaultMask = GPM_DRAG; + conn.minMod = 0; + conn.maxMod = (unsigned short)~0U; + + GpmFd = Gpm_Open(&conn, 0); + mouseShow(); +#endif + return 0; +} + +int ConDone() { + if (VtFd != -1) { + int tmp; + +#ifdef USE_GPM + if (GpmFd != -1) { + mouseHide(); + Gpm_Close(); + GpmFd = -1; + } +#endif + ioctl(VtFd, KDSKBMODE, K_XLATE); + tmp = tcsetattr(VtFd, 0, &Save_termios); + if (tmp) fprintf(stderr, "tcsetattr = %d\n", tmp); + } + return 0; +} + +int ConSuspend() { + int tmp; +#ifdef USE_GPM + mouseHide(); + Gpm_Close(); + GpmFd = -1; +#endif + ioctl(VtFd, KDSKBMODE, K_XLATE); + tmp = tcsetattr(VtFd, 0, &Save_termios); + if (tmp) fprintf(stderr, "tcsetattr = %d\n", tmp); + return 0; +} + +int ConContinue() { +#ifdef USE_GPM + Gpm_Connect conn; +#endif + struct termios newt; + int tmp; + + newt.c_lflag &= ~ (ICANON | ECHO | ISIG); + newt.c_iflag = 0; + newt.c_cc[VMIN] = 16; + newt.c_cc[VTIME] = 1; + tmp = tcsetattr(VtFd, TCSAFLUSH, &newt); + if (tmp) fprintf(stderr, "tcsetattr = %d\n", tmp); + + /* set keyboard to return MEDIUMRAW mode */ + if (ioctl(VtFd, KDSKBMODE, K_MEDIUMRAW) != 0) { + perror("ioctl KDSKBMODE"); + die("could not activate medium raw mode\n"); + } +#ifdef USE_GPM + conn.eventMask = (unsigned short)~0U; + conn.defaultMask = GPM_DRAG; + conn.minMod = 0; + conn.maxMod = (unsigned short)~0U; + + GpmFd = Gpm_Open(&conn, 0); + mouseShow(); +#endif + return 0; +} + +#ifdef USE_SCRNMAP +int conread(int fd, void *p, int len) { // len should be a multiple of 2 + char buf[512]; + char *c = (char *)p; + char *s = buf; + + if (noCharTrans || (len > 512)) { + return read(fd, p, len); + } else { + int rlen = read(fd, buf, len); + for (int n = 0; n < rlen; n += 2) { + *c++ = fromScreen[(unsigned char)*s++]; + *c++ = *s++; + } + return rlen; + } +} + +int conwrite(int fd, void *p, int len) { // len should be a multiple of 2 + char buf[512]; + char *s = (char *)p; + char *c = buf; + + if (noCharTrans || (len > 512)) { + return write(fd, p, len); + } else { + for (int n = 0; n < len; n += 2) { + *c++ = toScreen[(unsigned char)*s++]; + *c++ = *s++; + } + return write(fd, buf, len); + } +} +#else +#define conread(fd,b,len) read(fd,b,len) +#define conwrite(fd,b,len) write(fd,b,len) +#endif + +int ConClear() { + int X, Y; + TCell Cell = ' ' | (0x07 << 8); + ConQuerySize(&X, &Y); + ConSetBox(0, 0, X, Y, Cell); + ConSetCursorPos(0, 0); + return 0; +} + +int ConSetTitle(char *Title, char *STitle) { + return 0; +} +int ConGetTitle(char *Title, int MaxLen, char *STitle, int SMaxLen) { + *Title = 0; + return 0; +} + +int ConPutBox(int X, int Y, int W, int H, PCell Cell) { + int i, hidden = 0; + + for (i = 0; i < H; i++) { + if (LastMouseY == Y + i) { mouseHide(); hidden = 1; } + lseek(VcsFd, 4 + ((Y + i) * VideoCols + X) * 2, SEEK_SET); + conwrite(VcsFd, Cell, 2 * W); + Cell += W; + if (hidden) mouseShow(); + } + return 0; +} + +int ConGetBox(int X, int Y, int W, int H, PCell Cell) { + int i, hidden = 0; + + for (i = 0; i < H; i++) { + if (LastMouseY == Y + i) { mouseHide(); hidden = 1; } + lseek(VcsFd, 4 + ((Y + i) * VideoCols + X) * 2, SEEK_SET); + conread(VcsFd, Cell, 2 * W); + Cell += W; + if (hidden) mouseShow(); + } + return 0; +} + +int ConPutLine(int X, int Y, int W, int H, PCell Cell) { + int i, hidden = 0; + + for (i = 0; i < H; i++) { + if (LastMouseY == Y + i) { mouseHide(); hidden = 1; } + lseek(VcsFd, 4 + ((Y + i) * VideoCols + X) * 2, SEEK_SET); + conwrite(VcsFd, Cell, 2 * W); + if (hidden) mouseShow(); + } + return 0; +} + +int ConSetBox(int X, int Y, int W, int H, TCell Cell) { + TDrawBuffer B; + MoveCh(B, Cell & 0xFF, Cell >> 8, W); + ConPutLine(X, Y, W, H, B); + return 0; +} + +int ConScroll(int Way, int X, int Y, int W, int H, TAttr Fill, int Count) { + PCell C; + TDrawBuffer B; + + if (Count == 0 || Count > H) return 0; + C = (PCell)malloc(2 * W * H); + if (C == 0) + return -1; +#ifdef USE_SCRNMAP + noCharTrans = 1; +#endif + MoveCh(B, ' ', Fill, W); + ConGetBox(X, Y, W, H, C); + if (Way == csUp) { + ConPutBox(X, Y, W, H - Count, C + W * Count); + ConPutLine(X, Y + H - Count, W, Count, B); + } else { + ConPutBox(X, Y + Count, W, H - Count, C); + ConPutLine(X, Y, W, Count, B); + } +#ifdef USE_SCRNMAP + noCharTrans = 0; +#endif + free((void *)C); + return 0; +} + +int ConSetSize(int X, int Y) { + return -1; +} + +int ConQuerySize(int *X, int *Y) { + if (X) *X = VideoCols; + if (Y) *Y = VideoRows; + return 0; +} + +int ConSetCursorPos(int X, int Y) { + char pos[2]; + + if (X >= 0 && X < int(VideoCols)) CursorX = X; + if (Y >= 0 && Y < int(VideoRows)) CursorY = Y; + pos[0] = CursorX; + pos[1] = CursorY; + lseek(VcsFd, 2, SEEK_SET); + write(VcsFd, pos, 2); + return 0; +} + +int ConQueryCursorPos(int *X, int *Y) { + if (X) *X = CursorX; + if (Y) *Y = CursorY; + return 0; +} + +int ConShowCursor(void) { + return 0; +} + +int ConHideCursor(void) { + return 0; +} + +int ConCursorVisible(void) { + return 1; +} + +int ConSetMousePos(int X, int Y) { + return -1; +} + +int ConQueryMousePos(int *X, int *Y) { + if (X) *X = LastMouseX; + if (Y) *Y = LastMouseY; + return -1; +} + +int ConShowMouse(void) { + return -1; +} + +int ConHideMouse(void) { + return -1; +} + +int ConMouseVisible(void) { + return 0; +} + +int ConQueryMouseButtons(int *ButtonCount) { + if (ButtonCount) *ButtonCount = 0; + return 0; +} + +int GetEvent(TEvent *Event); +static TEvent Prev = { evNone }; + +int ConGetEvent(TEventMask EventMask, TEvent *Event, int WaitTime, int Delete) { + fd_set readfds; + struct timeval timeout; + + if (Prev.What != evNone) { + *Event = Prev; + if (Delete) Prev.What = evNone; + return 1; + } + Event->What = evNone; + + FD_ZERO(&readfds); + FD_SET(VtFd, &readfds); +#ifdef USE_GPM + if (GpmFd != -1) + FD_SET(GpmFd, &readfds); +#endif + for (int p = 0; p < MAX_PIPES; p++) + if (Pipes[p].used) + if (Pipes[p].fd != -1) + FD_SET(Pipes[p].fd, &readfds); + if (WaitTime == -1) { + if (select(sizeof(fd_set) * 8, &readfds, NULL, NULL, NULL) < 0) return -1; + } else { + timeout.tv_sec = WaitTime / 1000; + timeout.tv_usec = (WaitTime % 1000) * 1000; + if (select(sizeof(fd_set) * 8, &readfds, NULL, NULL, &timeout) < 0) return -1; + } + if (FD_ISSET(VtFd, &readfds)) { + GetKeyEvent(Event); + if (!Delete) + Prev = *Event; + return 1; +#ifdef USE_GPM + } else if (GpmFd != -1 && FD_ISSET(GpmFd, &readfds)) { + GetMouseEvent(Event); + if (!Delete) + Prev = *Event; + return 1; +#endif + } else { + for (int pp = 0; pp < MAX_PIPES; pp++) { + if (Pipes[pp].used) + if (Pipes[pp].fd != -1) + if (FD_ISSET(Pipes[pp].fd, &readfds)) { + if (Pipes[pp].notify) { + Event->What = evNotify; + Event->Msg.View = 0; + Event->Msg.Model = Pipes[pp].notify; + Event->Msg.Command = cmPipeRead; + Event->Msg.Param1 = pp; + Pipes[pp].stopped = 0; + } + //fprintf(stderr, "Pipe %d\n", Pipes[pp].fd); + return 0; + } + } + return -1; + } + return 0; +} + +int ConPutEvent(TEvent Event) { + Prev = Event; + return 0; +} + +int ConFlush(void) {return 0; } +int ConGrabEvents(TEventMask EventMask) { return 0; } + +int shift_state = 0; +int lock_state = 0; +int slock_state = 0; +char dead_key = 0; + +static const struct { + unsigned long KeySym; + unsigned long KeyCode; +} KeyTrans[] = { +{ K(KT_FN, K_F1), kbF1 }, +{ K(KT_FN, K_F2), kbF2 }, +{ K(KT_FN, K_F3), kbF3 }, +{ K(KT_FN, K_F4), kbF4 }, +{ K(KT_FN, K_F5), kbF5 }, +{ K(KT_FN, K_F6), kbF6 }, +{ K(KT_FN, K_F7), kbF7 }, +{ K(KT_FN, K_F8), kbF8 }, +{ K(KT_FN, K_F9), kbF9 }, +{ K(KT_FN, K_F10), kbF10 }, +{ K(KT_FN, K_F11), kbF11 }, +{ K(KT_FN, K_F12), kbF12 }, +{ K(KT_FN, K_INSERT), kbIns | kfGray }, +{ K(KT_FN, K_REMOVE), kbDel | kfGray }, +{ K(KT_FN, K_FIND), kbHome | kfGray }, +{ K(KT_FN, K_SELECT), kbEnd | kfGray }, +{ K(KT_FN, K_PGUP), kbPgUp | kfGray }, +{ K(KT_FN, K_PGDN), kbPgDn | kfGray }, +{ K(KT_CUR, K_UP), kbUp | kfGray }, +{ K(KT_CUR, K_DOWN), kbDown | kfGray }, +{ K(KT_CUR, K_LEFT), kbLeft | kfGray }, +{ K(KT_CUR, K_RIGHT), kbRight | kfGray }, +{ K(KT_SPEC, K_ENTER), kbEnter }, +{ K(KT_PAD, K_PENTER), kbEnter | kfGray }, +{ K(KT_PAD, K_PPLUS), '+' | kfGray }, +{ K(KT_PAD, K_PMINUS), '-' | kfGray }, +{ K(KT_PAD, K_PSTAR), '*' | kfGray }, +{ K(KT_PAD, K_PSLASH), '/' | kfGray }, +{ K(KT_PAD, K_P0), kbIns }, +{ K(KT_PAD, K_PDOT), kbDel }, +{ K(KT_PAD, K_P1), kbEnd }, +{ K(KT_PAD, K_P2), kbDown }, +{ K(KT_PAD, K_P3), kbPgDn }, +{ K(KT_PAD, K_P4), kbLeft }, +{ K(KT_PAD, K_P5), kbCenter }, +{ K(KT_PAD, K_P6), kbRight }, +{ K(KT_PAD, K_P7), kbHome }, +{ K(KT_PAD, K_P8), kbUp }, +{ K(KT_PAD, K_P9), kbPgUp }, +{ K(KT_FN, K_PAUSE), kbPause }, +{ K(KT_LATIN, 27), kbEsc }, +{ K(KT_LATIN, 13), kbEnter }, +{ K(KT_LATIN, 8), kbBackSp }, +{ K(KT_LATIN, 127), kbDel }, +{ K(KT_LATIN, 9), kbTab }, +{ K(KT_SHIFT, KG_SHIFT), kbShift | kfSpecial | kfModifier }, +{ K(KT_SHIFT, KG_SHIFTL), kbShift | kfSpecial | kfModifier }, +{ K(KT_SHIFT, KG_SHIFTR), kbShift | kfSpecial | kfModifier | kfGray }, +{ K(KT_SHIFT, KG_CTRL), kbCtrl | kfSpecial | kfModifier }, +{ K(KT_SHIFT, KG_CTRLL), kbCtrl | kfSpecial | kfModifier }, +{ K(KT_SHIFT, KG_CTRLR), kbCtrl | kfSpecial | kfModifier | kfGray }, +{ K(KT_SHIFT, KG_ALT), kbAlt | kfSpecial | kfModifier }, +{ K(KT_SHIFT, KG_ALTGR), kbAlt | kfSpecial | kfModifier | kfGray }, +{ 0, 0 } +}; + +struct { + unsigned long KeySym; + char Diacr; +} DeadTrans[] = { +{ K_DGRAVE, '`' }, +{ K_DACUTE, '\'' }, +{ K_DCIRCM, '^' }, +{ K_DTILDE, '~' }, +{ K_DDIERE, '"' }, +{ K_DCEDIL, ',' } +}; + +int GetKeyEvent(TEvent *Event) { + char keycode; + + Event->What = evNone; + + if (read(VtFd, &keycode, 1) != 1) + return -1; + + int key = keycode & 0x7F; + int press = (keycode & 0x80) ? 0 : 1; + unsigned int keysym; + int rc; + struct kbentry kbe; + int shift_final; + int ShiftFlags; + TKeyCode KeyCode; + + kbe.kb_index = key; + kbe.kb_table = 0; + rc = ioctl(VtFd, KDGKBENT, &kbe); + keysym = kbe.kb_value; + + //printf("rc = %d, value = %04X, ktype=%d, kval=%d\n", + // rc, keysym, KTYP(keysym), KVAL(keysym)); + + int ksv = KVAL(keysym); + + switch(KTYP(keysym)) { + case KT_SHIFT: + // :-(((, have to differentiate between shifts. + if (ksv == KG_SHIFT) { + if (key == 54) + ksv = KG_SHIFTR; + else + ksv = KG_SHIFTL; + } else if (ksv == KG_CTRL) { + if (key == 97) + ksv = KG_CTRLR; + else + ksv = KG_CTRLL; + } + if (press) + shift_state |= (1 << ksv); + else + shift_state &= ~(1 << ksv); + break; + case KT_LOCK: +// if (press) +// lock_state |= (1 << ksv); +// else +// lock_state &= ~(1 << ksv); + if (press) lock_state ^= (1 << ksv); + break; + case KT_SLOCK: + if (press) + slock_state |= (1 << ksv); + else + slock_state &= ~(1 << ksv); + break; + } + + shift_final = shift_state ^ lock_state ^ slock_state; + + if (shift_final & ((1 << KG_SHIFT) | + (1 << KG_SHIFTL) | + (1 << KG_SHIFTR))) + { + shift_final |= (1 << KG_SHIFT); + shift_final &= ~( (1 << KG_SHIFTL) | (1 << KG_SHIFTR) ); + } + if (shift_final & ((1 << KG_CTRL) | + (1 << KG_CTRLL) | + (1 << KG_CTRLR))) + { + shift_final |= (1 << KG_CTRL); + shift_final &= ~( (1 << KG_CTRLL) | (1 << KG_CTRLR) ); + } + + ShiftFlags = 0; + if ((shift_final & (1 << KG_SHIFT)) || + (shift_final & (1 << KG_SHIFTL)) || + (shift_final & (1 << KG_SHIFTR))) + ShiftFlags |= kfShift; + if ((shift_final & (1 << KG_CTRL)) || + (shift_final & (1 << KG_CTRLL)) || + (shift_final & (1 << KG_CTRLR))) + ShiftFlags |= kfCtrl; +// if ((shift_final & (1 << KG_ALT)) || +// (shift_final & (1 << KG_ALTGR))) + if (shift_final & (1 << KG_ALT)) + ShiftFlags |= kfAlt; + + // printf("shift: %X, lock: %X, slock: %X, final: %X, ShiftFlags: %X\n", + // shift_state, lock_state, slock_state, shift_final, ShiftFlags); + + if (KTYP(keysym) != KT_SLOCK) + slock_state = 0; + + KeyCode = 0; + if (key == 14 && keysym == K(KT_LATIN,127)) { + // we are running on a system with broken backspace key + KeyCode = kbBackSp; + } else for(unsigned int i = 0; i < sizeof(KeyTrans) / sizeof(KeyTrans[0]); i++) { + if (KeyTrans[i].KeySym == keysym) { + KeyCode = KeyTrans[i].KeyCode; + break; + } + } + if (KeyCode == 0) { + switch (KTYP(keysym)) { + case KT_CONS: + case KT_FN: + //case KT_SPEC: + case KT_LOCK: + case KT_SLOCK: + //case KT_META: + case KT_CUR: + + default: + //if (!(shift_final & KG_ALTGR)) + // break; + dead_key = 0; + break; + + case KT_SHIFT: + break; + case KT_LETTER: + // take caps into account + if (0) { + ShiftFlags ^= kfShift; + shift_final ^= (1 << KG_SHIFT); + } + // no break + case KT_LATIN: +// if (shift_final & (1 << KG_ALTGR)) +// ShiftFlags &= ~kfAlt; + + if (ShiftFlags & kfAlt) + shift_final &= + ~(1 << KG_SHIFT); + + kbe.kb_index = key; + kbe.kb_table = shift_final; + rc = ioctl(VtFd, KDGKBENT, &kbe); + if (rc != 0) + break; + + keysym = kbe.kb_value; + + //if (KTYP(keysym) != KT_LATIN && + // KTYP(keysym) != KT_LETTER && + // KTYP(keysym) != KT_ASCII) + // break; + + KeyCode = KVAL(keysym); + if (ShiftFlags & kfAlt) + KeyCode = toupper(KeyCode); + + if (KTYP(keysym) == KT_DEAD) { + for (int i = 0;(unsigned) i < sizeof(DeadTrans) / sizeof(DeadTrans[0]); i++) { + if (DeadTrans[i].KeySym == keysym) { + dead_key = DeadTrans[i].Diacr; + return -1; + } + } + dead_key = 0; + return -1; + } + if (! (ShiftFlags & (kfAlt | kfCtrl)) && dead_key) { + for (int i = 0; (unsigned) i < diacr_table.kb_cnt; i++) { + if (diacr_table.kbdiacr[i].base == KeyCode && + diacr_table.kbdiacr[i].diacr == dead_key) { + KeyCode=diacr_table.kbdiacr[i].result; + break; + } + } + } + dead_key = 0; + + break; + } + } + + if (KeyCode == 0) + return -1; + + if (ShiftFlags & kfCtrl) + if (KeyCode < 32) + KeyCode += 64; + + KeyCode |= ShiftFlags; + + if (!press) + KeyCode |= kfKeyUp; + + if (KeyCode != 0) { + + if (KTYP(keysym) != KT_SHIFT) + dead_key = 0; + + if (KeyCode & kfKeyUp) + Event->What = evKeyUp; + else + Event->What = evKeyDown; + Event->Key.Code = KeyCode & ~kfKeyUp; + + + // switching consoles should be done by the kernel, but + // it is not (why, since I am not using VT_PROCESS??). + // this has a delay if the app is working. + // there is also a problem with shift-states (should update it + // after getting back, but how to know when that happens, without + // using VT_PROCESS?). + { + int vc = -1; + +// switch (kbCode(Event->Key.Code) | kfCtrl) { + switch (kbCode(Event->Key.Code)) { + case kfAlt | kfCtrl | kbF1: vc = 1; break; + case kfAlt | kfCtrl | kbF2: vc = 2; break; + case kfAlt | kfCtrl | kbF3: vc = 3; break; + case kfAlt | kfCtrl | kbF4: vc = 4; break; + case kfAlt | kfCtrl | kbF5: vc = 5; break; + case kfAlt | kfCtrl | kbF6: vc = 6; break; + case kfAlt | kfCtrl | kbF7: vc = 7; break; + case kfAlt | kfCtrl | kbF8: vc = 8; break; + case kfAlt | kfCtrl | kbF9: vc = 9; break; + case kfAlt | kfCtrl | kbF10: vc = 10; break; + case kfAlt | kfCtrl | kbF11: vc = 11; break; + case kfAlt | kfCtrl | kbF12: vc = 12; break; + } + if (vc != -1) { + /* perform the console switch */ + ioctl(VtFd, VT_ACTIVATE, vc); + Event->What = evNone; +// shift_state = lock_state = slock_state = 0; // bad + shift_state = slock_state = 0; // bad + return -1; + } + } + + return 0; + } + return -1; +} + +int GetMouseEvent(TEvent *Event) { +#ifdef USE_GPM + Gpm_Event e; + + Event->What = evNone; + int rc = Gpm_GetEvent(&e); + if (rc == 0) { + Gpm_Close(); + GpmFd = -1; + } else if (rc == -1) { + } else { + //Gpm_FitEvent(&e); + if ((e.type & GPM_MOVE) || (e.type & GPM_DRAG)) + Event->What = evMouseMove; + else if (e.type & GPM_DOWN) + Event->What = evMouseDown; + else if (e.type & GPM_UP) + Event->What = evMouseUp; + else return 0; + + Event->Mouse.Count = (e.type & GPM_SINGLE) ? 1 + : (e.type & GPM_DOUBLE) ? 2 + : (e.type & GPM_TRIPLE) ? 3 : 1; + Event->Mouse.Buttons = + ((e.buttons & GPM_B_LEFT) ? 1 : 0) | + ((e.buttons & GPM_B_RIGHT) ? 2 : 0) | + ((e.buttons & GPM_B_MIDDLE) ? 4 : 0); + + e.x--; + e.y--; + + if (e.x < 0) e.x = 0; + if (e.y < 0) e.y = 0; + if (e.x >= int(VideoCols)) e.x = VideoCols - 1; + if (e.y >= int(VideoRows)) e.y = VideoRows - 1; + + Event->Mouse.X = e.x; + Event->Mouse.Y = e.y; + + Event->Mouse.KeyMask = + ((e.modifiers & 1) ? kfShift : 0) | + ((e.modifiers & (2 | 8)) ? kfAlt : 0) | + ((e.modifiers & 4) ? kfCtrl : 0); + + if (LastMouseX != e.x || + LastMouseY != e.y) + { + mouseHide(); + LastMouseX = e.x; + LastMouseY = e.y; + mouseShow(); + } + } + +#else + Event->What = evNone; +#endif + return 0; +} + +int ConSetCursorSize(int Start, int End) { + return 0; +} + +static PCell +SavedScreen = 0; +static int SavedX, SavedY, SaveCursorPosX, SaveCursorPosY; + +int SaveScreen() { + if (SavedScreen) + free(SavedScreen); + + ConQuerySize(&SavedX, &SavedY); + + SavedScreen = (PCell) malloc(SavedX * SavedY * sizeof(PCell)); + + if (SavedScreen) + ConGetBox(0, 0, SavedX, SavedY, SavedScreen); + ConQueryCursorPos(&SaveCursorPosX, &SaveCursorPosY); + return 0; +} + +int RestoreScreen() { + if (SavedScreen) { + ConPutBox(0, 0, SavedX, SavedY, SavedScreen); + ConSetCursorPos(SaveCursorPosX, SaveCursorPosY); + } + return 1; +} + +GUI::GUI(int &argc, char **argv, int XSize, int YSize) { + fArgc = argc; + fArgv = argv; + ::ConInit(-1, -1); + SaveScreen(); + ::ConSetSize(XSize, YSize); + gui = this; +} + +GUI::~GUI() { + RestoreScreen(); + ::ConDone(); + + if(SavedScreen) + { + free(SavedScreen); + SavedScreen = 0; + } + + gui = 0; +} + +int GUI::ConSuspend(void) { + RestoreScreen(); + return ::ConSuspend(); +} + +int GUI::ConContinue(void) { + SaveScreen(); + return ::ConContinue(); +} + +int GUI::ShowEntryScreen() { + TEvent E; + + ConHideMouse(); + RestoreScreen(); + do { gui->ConGetEvent(evKeyDown, &E, -1, 1, 0); } while (E.What != evKeyDown); + ConShowMouse(); + if (frames) + frames->Repaint(); + return 1; +} + +int GUI::OpenPipe(char *Command, EModel *notify) { + int i; + + for (i = 0; i < MAX_PIPES; i++) { + if (Pipes[i].used == 0) { + int pfd[2]; + + Pipes[i].id = i; + Pipes[i].notify = notify; + Pipes[i].stopped = 1; + + if (pipe((int *)pfd) == -1) + return -1; + + switch (Pipes[i].pid = fork()) { + case -1: /* fail */ + return -1; + case 0: /* child */ + signal(SIGPIPE, SIG_DFL); + VtFd = -1; // for atexit handler + close(VtFd); + close(pfd[0]); + close(0); + dup2(pfd[1], 1); + dup2(pfd[1], 2); + close(pfd[1]); + exit(system(Command)); + default: + close(pfd[1]); + fcntl(pfd[0], F_SETFL, O_NONBLOCK); + Pipes[i].fd = pfd[0]; + } + Pipes[i].used = 1; + //fprintf(stderr, "Pipe Open: %d\n", i); + return i; + } + } + return -1; +} + +int GUI::SetPipeView(int id, EModel *notify) { + if (id < 0 || id > MAX_PIPES) + return -1; + if (Pipes[id].used == 0) + return -1; + //fprintf(stderr, "Pipe View: %d %08X\n", id, notify); + Pipes[id].notify = notify; + return 0; +} + +int GUI::ReadPipe(int id, void *buffer, int len) { + int rc; + + if (id < 0 || id > MAX_PIPES) + return -1; + if (Pipes[id].used == 0) + return -1; + //fprintf(stderr, "Pipe Read: Get %d %d\n", id, len); + + rc = read(Pipes[id].fd, buffer, len); + //fprintf(stderr, "Pipe Read: Got %d %d\n", id, len); + if (rc == 0) { + close(Pipes[id].fd); + Pipes[id].fd = -1; + return -1; + } + if (rc == -1) { + Pipes[id].stopped = 1; + return 0; + } + return rc; +} + +int GUI::ClosePipe(int id) { + int status = -1; + + if (id < 0 || id > MAX_PIPES) + return -1; + if (Pipes[id].used == 0) + return -1; + if (Pipes[id].fd != -1) + close(Pipes[id].fd); + kill(Pipes[id].pid, SIGHUP); + alarm(1); + waitpid(Pipes[id].pid, &status, 0); + alarm(0); + //fprintf(stderr, "Pipe Close: %d\n", id); + Pipes[id].used = 0; + return WEXITSTATUS(status); +} + +int GUI::RunProgram(int mode, char *Command) { + int rc, W, H, W1, H1; + + ConQuerySize(&W, &H); + ConHideMouse(); + ConSuspend(); + + if (*Command == 0) // empty string = shell + Command = getenv("SHELL"); + + rc = system(Command); + + ConContinue(); + ConShowMouse(); + ConQuerySize(&W1, &H1); + + if (W != W1 || H != H1) { + frames->Resize(W1, H1); + } + frames->Repaint(); + return rc; +} + +char ConGetDrawChar(int index) { + static const char tab[] = "Ú¿ÀÙijÂôÁÅ\x1Aúı°\x1B\x1A"; + static const char tab_iso[] = "++++-|+++++>.*-^v :[>"; + //static char tab[] = "\x0D\x0C\x0E\x0B\x12\x19____+>\x1F\x01\x12 "; + static int use = 0; + + assert(index >= 0 && index < int(strlen(tab))); + + if (use == 0) { + char * c = getenv("ISOCONSOLE"); + use = (c == NULL) ? 1 : 2; + } + + if (use == 2) + return tab_iso[index]; + +#ifdef USE_SCRNMAP + return fromScreen[tab[index]]; +#else + return tab[index]; +#endif +} diff --git a/src/con_nt.cpp b/src/con_nt.cpp new file mode 100644 index 0000000..0281fd7 --- /dev/null +++ b/src/con_nt.cpp @@ -0,0 +1,1925 @@ +/* con_nt.cpp + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +/* some functionality is now shared with g_text.cpp and g_draw.cpp */ +/* new os/2 code needs to be merged with this */ +/* the console APIs on win'95 seem to be really screwed up */ + +/* + * 10/13/96 Jal: + * Rebuilt for Windows NT, generic; no port/Watcom code should + * be needed to compile (jal). + * Removed most mouse handling code (unnecessary), added pipe handler by + * porting the OS/2 version to NT. + * Solved some bugs with regard to the TCell problem. + * + * 10/28/96 Jal: + * Started to replace threaded pipe code with nonthreaded code, using + * overlapped I/O. + * + * Wed Jan 15 1997 (Jal): + * - The Grey-Alt-+ key and some other keys were not recognised. This + * was because NT didn't mark these as "enhanced" keys. Now the code + * translates some (scancode,ascii) pairs to the enhanced keyboard. + * The table was already present! + * - To solve the "flashing cursor" problem: now doesn't enter FTE + * mainloop when console returns empty action.. + * + */ +//#define WIN32_LEAN_AND_MEAN 1 +#include "windows.h" +#include + +#include +#include "sysdep.h" +#include "console.h" +#include "gui.h" + +#define True 1 +#define False 0 + + +static int Initialized = 0; +static int MousePresent = 0; +static int CursorVisible = 1; /* 1 means visible */ +static int MouseVisible = 0; /* 0 means hidden */ +static TEvent MouseEv = { evNone }; +static TEvent EventBuf = { evNone }; +static TEventMask EventMask; + +static HANDLE ConOut; +static HANDLE ConIn; +static HANDLE OurConOut; +static DWORD OldConsoleMode; + +static int LastMouseX = 0; +static int LastMouseY = 0; +//static int isWin95 = 0; + +int codepage; + +#define dbm(x) //printf(x), Sleep(3000) + + +#if 0 +void dbg(const char* s, ...) /*FOLD00*/ +{ +} +#else + +void dbg(const char* s, ...) /*FOLD00*/ +{ + char buf[256]; + va_list args; + + va_start(args, s); + vsprintf(buf, s, args); + va_end(args); + OutputDebugString(buf); +} +#endif + + +static void DrawCursor(int Show) { /*FOLD00*/ + CONSOLE_CURSOR_INFO cci; + + GetConsoleCursorInfo(OurConOut, &cci); + cci.bVisible = Show ? TRUE : FALSE; + SetConsoleCursorInfo(OurConOut, &cci); +} + +#define NUMITEMS(x) (sizeof(x) / sizeof(x[0])) + +#if 1 +/* + * Translation table 1: translate (scan,asciicode) of the input event to a + * valid FTE keystroke. This is used because NT sometimes "forgets" to flag + * special keys as "enhanced" (grey) keys.. + */ +static struct { + USHORT CharScan; + TKeyCode KeyCode; +} TransCharScan[] = { + { 0x0100, kbEsc }, { 0x011B, kbEsc }, + { 0x1C0D, kbEnter }, { 0x1C0A, kbEnter }, + { 0x1C00, kbEnter }, { 0xE00D, kbEnter | kfGray }, + { 0xA600, kbEnter | kfGray }, { 0xE00A, kbEnter | kfGray }, + { 0x0E08, kbBackSp }, { 0x0E7F, kbBackSp }, + { 0x0E00, kbBackSp }, { 0x0F09, kbTab }, + { 0x9400, kbTab }, { 0xA500, kbTab }, + { 0x0F00, kbTab }, { 0x4E00, '+' | kfGray }, + { 0x9000, '+' | kfGray }, { 0x4E2B, '+' | kfGray }, + { 0x4A00, '-' | kfGray }, { 0x8E00, '-' | kfGray }, + { 0x4A2D, '-' | kfGray }, { 0x3700, '*' | kfGray }, + { 0x9600, '*' | kfGray }, { 0x372A, '*' | kfGray }, + { 0xE02F, '/' | kfGray }, { 0xA400, '/' | kfGray }, + { 0x9500, '/' | kfGray }, { 0x0300, 0 } +}; +#endif + +#if 0 +static struct { + int ScanCode; + TKeyCode KeyCode; +} TransScan[] = { + { 0x78, '1' }, { 0x79, '2' }, { 0x7A, '3' }, { 0x7B, '4' }, { 0x7C, '5' }, + { 0x7D, '6' }, { 0x7E, '7' }, { 0x7F, '8' }, { 0x80, '9' }, { 0x81, '0' }, + + { 0x10, 'Q' }, { 0x11, 'W' }, { 0x12, 'E' }, { 0x13, 'R' }, { 0x14, 'T' }, + { 0x15, 'Y' }, { 0x16, 'U' }, { 0x17, 'I' }, { 0x18, 'O' }, { 0x19, 'P' }, + + { 0x1E, 'A' }, { 0x1F, 'S' }, { 0x20, 'D' }, { 0x21, 'F' }, { 0x22, 'G' }, + { 0x23, 'H' }, { 0x24, 'J' }, { 0x25, 'K' }, { 0x26, 'L' }, + + { 0x2C, 'Z' }, { 0x2D, 'X' }, { 0x2E, 'C' }, { 0x2F, 'V' }, { 0x30, 'B' }, + { 0x31, 'N' }, { 0x32, 'M' }, + + { 0x29, '`' }, { 0x82, '-' }, { 0x83, '=' }, { 0x2B, '\\' }, { 0x1A, '[' }, + { 0x1B, ']' }, { 0x27, ';' }, { 0x28, '\'' }, { 0x33, ',' }, { 0x34, '.' }, + { 0x35, '/' }, { 0x37, '*' }, { 0x4E, '+' }, { 0x4A, '-' }, + + { 0x3B, kbF1 }, { 0x3C, kbF2 }, { 0x3D, kbF3 }, + { 0x3E, kbF4 }, { 0x3F, kbF5 }, { 0x40, kbF6 }, + { 0x41, kbF7 }, { 0x42, kbF8 }, { 0x43, kbF9 }, + { 0x44, kbF10 }, { 0x85, kbF11 }, { 0x86, kbF12 }, + + { 0x54, kbF1 }, { 0x55, kbF2 }, { 0x56, kbF3 }, + { 0x57, kbF4 }, { 0x58, kbF5 }, { 0x59, kbF6 }, + { 0x5A, kbF7 }, { 0x5B, kbF8 }, { 0x5C, kbF9 }, + { 0x5D, kbF10 }, { 0x87, kbF11 }, { 0x88, kbF12 }, + + { 0x5E, kbF1 }, { 0x5F, kbF2 }, { 0x60, kbF3 }, + { 0x61, kbF4 }, { 0x62, kbF5 }, { 0x63, kbF6 }, + { 0x64, kbF7 }, { 0x65, kbF8 }, { 0x66, kbF9 }, + { 0x67, kbF10 }, { 0x89, kbF11 }, { 0x8A, kbF12 }, + + { 0x68, kbF1 }, { 0x69, kbF2 }, { 0x6A, kbF3 }, + { 0x6B, kbF4 }, { 0x6C, kbF5 }, { 0x6D, kbF6 }, + { 0x6E, kbF7 }, { 0x6F, kbF8 }, { 0x70, kbF9 }, + { 0x71, kbF10 }, { 0x8B, kbF11 }, { 0x8C, kbF12 }, + + { 0x47, kbHome }, { 0x48, kbUp }, { 0x49, kbPgUp }, + { 0x4B, kbLeft }, { 0x4C, kbCenter}, { 0x4D, kbRight }, + { 0x4F, kbEnd }, { 0x50, kbDown }, { 0x51, kbPgDn }, + { 0x52, kbIns }, { 0x53, kbDel }, + + { 0x77, kbHome }, { 0x8D, kbUp }, { 0x84, kbPgUp }, + { 0x73, kbLeft }, { 0x74, kbRight }, + { 0x75, kbEnd }, { 0x91, kbDown }, { 0x76, kbPgDn }, + { 0x92, kbIns }, { 0x93, kbDel }, + + { 0x97, kbHome | kfGray }, { 0x98, kbUp | kfGray }, { 0x99, kbPgUp | kfGray }, + { 0x9B, kbLeft | kfGray }, { 0x9D, kbRight | kfGray }, + { 0x9F, kbEnd | kfGray }, { 0xA0, kbDown | kfGray }, { 0xA1, kbPgDn | kfGray }, + { 0xA2, kbIns | kfGray }, { 0xA3, kbDel | kfGray } +}; +#endif + + +struct { + SHORT VirtCode; + unsigned long KeyCode; +} VirtTab[] = +{ + { 112, kbF1 }, + { 113, kbF2 }, + { 114, kbF3 }, + { 115, kbF4 }, + { 116, kbF5 }, + { 117, kbF6 }, + { 118, kbF7 }, + { 119, kbF8 }, + { 120, kbF9 }, + { 121, kbF10 }, + { 122, kbF11 }, + { 123, kbF12 }, + + { 35, kbEnd }, + { 36, kbHome }, + { 33, kbPgUp }, + { 34, kbPgDn }, + { 38, kbUp }, + { 37, kbLeft }, + { 39, kbRight }, + { 40, kbDown }, + { 45, kbIns }, + { 46, kbDel }, + + { 27, kbEsc }, + { 13, kbEnter }, + { 8, kbBackSp }, + { 32, kbSpace }, + { 9, kbTab }, + + { 0, 0 } +}; + +char shftwrng[] = "~!@#$%^&*()_+{}|:\"<>?"; +char shftright[] = "`1234567890-=[]\\;',./"; + +int ReadConsoleEvent(TEvent *E) /*FOLD00*/ +{ + /* + * Reads and interprets the console event. It is called when console input + * handle is signalled. To prevent flashing cursors this routine returns + * F if there's nothing to do; this causes the caller to loop without + * returning to the FTE mainloop. + */ + INPUT_RECORD inp; + DWORD nread; + TKeyCode Ch = 0; + TKeyCode flg = 0; + ULONG flags; + int I, i; + + ReadConsoleInput(ConIn, &inp, 1, &nread); + if (nread != 1) return False; // Nothing read after signal?? + + switch (inp.EventType) + { + case WINDOW_BUFFER_SIZE_EVENT: + //** Resized the window. Make FTE use the new size.. + frames->Resize(inp.Event.WindowBufferSizeEvent.dwSize.X, inp.Event.WindowBufferSizeEvent.dwSize.Y); + frames->Repaint(); + return True; + + case KEY_EVENT: + if (inp.Event.KeyEvent.bKeyDown) { + if ((inp.Event.KeyEvent.dwControlKeyState & CAPSLOCK_ON) && + inp.Event.KeyEvent.wVirtualKeyCode != 106 && + inp.Event.KeyEvent.wVirtualKeyCode != 109 && + inp.Event.KeyEvent.wVirtualKeyCode != 107) + { + if (!(inp.Event.KeyEvent.dwControlKeyState & SHIFT_PRESSED)) { + for (i=0; shftwrng[i]; i++) { + if (inp.Event.KeyEvent.uChar.AsciiChar == shftwrng[i]) { + inp.Event.KeyEvent.uChar.AsciiChar = shftright[i]; + break; + } + } + } + else { + for (i=0; shftright[i]; i++) { + if (inp.Event.KeyEvent.uChar.AsciiChar == shftright[i]) { + inp.Event.KeyEvent.uChar.AsciiChar = shftwrng[i]; + break; + } + } + } + } + } + //** Skip shift, control and alt key stuff. + switch(inp.Event.KeyEvent.wVirtualKeyCode) + { case VK_SHIFT: case VK_CONTROL: case VK_MENU: case VK_PAUSE: + case VK_CAPITAL: case VK_LWIN: case VK_RWIN: case VK_APPS: + return False; + } + + //** Distill FTE flags from the NT flags. This fails for some keys + //** because NT has an oddity with enhanced keys (Alt-Grey-+ etc). + flags = inp.Event.KeyEvent.dwControlKeyState; + if (flags & (/*RIGHT_ALT_PRESSED |*/ LEFT_ALT_PRESSED)) flg |= kfAlt; + if (flags & (RIGHT_CTRL_PRESSED | LEFT_CTRL_PRESSED)) flg |= kfCtrl; + if (flags & (RIGHT_ALT_PRESSED)) flg &= ~kfCtrl; + if (flags & SHIFT_PRESSED) flg |= kfShift; + if (flags & ENHANCED_KEY) flg |= kfGray; + +#if 0 + dbg("key1: %s, vk=%x, vscan=%x, flags=%x, rep=%d, ascii=%x (%c).\n", + inp.Event.KeyEvent.bKeyDown ? "down" : "up", + inp.Event.KeyEvent.wVirtualKeyCode, + inp.Event.KeyEvent.wVirtualScanCode, + flags, + inp.Event.KeyEvent.wRepeatCount, + inp.Event.KeyEvent.uChar.AsciiChar, + inp.Event.KeyEvent.uChar.AsciiChar); +#endif + + Ch = 0; + + // handle special case when user with scandinavian keyboard presses + // alt-gr + special key and then spacebar + if (inp.Event.KeyEvent.bKeyDown) { + if ((inp.Event.KeyEvent.wVirtualKeyCode == 0x20) && + (inp.Event.KeyEvent.wVirtualScanCode == 0x39)) + { + switch(inp.Event.KeyEvent.uChar.AsciiChar) + { + case '~': Ch = '~'; break; + case '^': Ch = '^'; break; + case '`': Ch = '`'; break; + case 'ï': Ch = 'ï'; break; + } + } + } + + //** Translate VK codes to FTE codes, + if (Ch == 0) + { + for (I = 0; I < sizeof(VirtTab)/sizeof(VirtTab[0]); I++) + if (VirtTab[I].VirtCode == inp.Event.KeyEvent.wVirtualKeyCode) + { + Ch = VirtTab[I].KeyCode; + break; + } + } + + //** Not a virtual key-> do charscan translation, if needed; + if(Ch == 0) + { + unsigned int cc = ((inp.Event.KeyEvent.wVirtualScanCode << 8) | (unsigned char)inp.Event.KeyEvent.uChar.AsciiChar); + for(I = 0; I < NUMITEMS(TransCharScan); I++) + { + if(cc == TransCharScan[I].CharScan) + { + Ch = TransCharScan[I].KeyCode; + break; + } + } + } + if (Ch == 0) + { + if ((Ch = (TKeyCode) (unsigned char)inp.Event.KeyEvent.uChar.AsciiChar) != 0) + { + if (flg & kfAlt) Ch = toupper(Ch); + } + } + + if (Ch == 0) //** Odd: cannot distill keycode. + return False; + + if (flg & kfCtrl) + if (Ch < 32) + Ch += 64; + + E->Key.Code = Ch | flg; // Set FTE keycode, + E->What = inp.Event.KeyEvent.bKeyDown ? evKeyDown : evKeyUp; + return True; + + case MOUSE_EVENT: + LastMouseX = E->Mouse.X = inp.Event.MouseEvent.dwMousePosition.X; + LastMouseY = E->Mouse.Y = inp.Event.MouseEvent.dwMousePosition.Y; + flags = inp.Event.MouseEvent.dwControlKeyState; + if (flags & (RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED)) flg |= kfAlt; + if (flags & (RIGHT_CTRL_PRESSED | LEFT_CTRL_PRESSED)) flg |= kfCtrl; + if (flags & SHIFT_PRESSED) flg |= kfShift; + E->Mouse.KeyMask = flg; + E->Mouse.Buttons = (unsigned short)inp.Event.MouseEvent.dwButtonState; + E->Mouse.Count = 1; + if (inp.Event.MouseEvent.dwEventFlags & DOUBLE_CLICK) + E->Mouse.Count = 2; + if (inp.Event.MouseEvent.dwEventFlags == MOUSE_MOVED) + { + E->What = evMouseMove; + //puts("Move"); + } + else + { + static unsigned short mb = 0; + + if (inp.Event.MouseEvent.dwButtonState & ~mb) + { + E->What = evMouseDown; + E->Mouse.Buttons = ((unsigned short)inp.Event.MouseEvent.dwButtonState) & ~mb; + //puts("Down"); + } + else + { + E->What = evMouseUp; + E->Mouse.Buttons = mb & ~((unsigned short)inp.Event.MouseEvent.dwButtonState); + //puts("Up"); + } + mb = (unsigned short)inp.Event.MouseEvent.dwButtonState; + } + return True; + } + return False; +} + + +int ConInit(int /*XSize*/, int /*YSize*/) { /*FOLD00*/ + if (Initialized) return 0; + + EventBuf.What = evNone; + MousePresent = 0; //MOUSInit(); + + //** Get NT/Win95 flag, + OSVERSIONINFO oi; + + oi.dwOSVersionInfoSize = sizeof(oi); + GetVersionEx((LPOSVERSIONINFO) &oi); + //isWin95 = (oi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS); + + ConOut = GetStdHandle(STD_OUTPUT_HANDLE); + ConIn = GetStdHandle(STD_INPUT_HANDLE); + codepage = GetConsoleCP(); + GetConsoleMode(ConIn, &OldConsoleMode); + SetConsoleMode(ConIn, + ENABLE_WINDOW_INPUT | + ENABLE_MOUSE_INPUT); + OurConOut = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE, + 0, NULL, + CONSOLE_TEXTMODE_BUFFER, NULL); + ConContinue(); + + Initialized = 1; + return 0; +} + +int ConDone(void) { /*FOLD00*/ + ConSuspend(); + CloseHandle(OurConOut); + return 0; +} + +int ConSuspend(void) { /*FOLD00*/ + SetConsoleActiveScreenBuffer(ConOut); + SetConsoleMode(ConIn, OldConsoleMode); + return 0; +} + +int ConContinue(void) { /*FOLD00*/ + SetConsoleActiveScreenBuffer(OurConOut); + GetConsoleMode(ConIn, &OldConsoleMode); + SetConsoleMode(ConIn, ENABLE_WINDOW_INPUT | ENABLE_MOUSE_INPUT); + { + SetConsoleOutputCP(codepage); + SetConsoleCP(codepage); + } + return 0; +} + +int ConClear(void) { /*FOLD00*/ + int W, H; + TDrawBuffer B; + + MoveChar(B, 0, ConMaxCols, ' ', 0x07, 1); + if ((ConQuerySize(&W, &H) == 0) && + ConSetBox(0, 0, W, H, B[0])) return 0; + return -1; +} + + +#if 0 // Mouse control not necessary when using console functions. +/*--------------------------------------------------------------------------*/ +/* CLASS: tMouHelp is used to control mouse cursor visibility during */ +/* screen updates. */ +/*--------------------------------------------------------------------------*/ +class tMouHelp +{ +protected: + int mh_x, mh_y; // Current mouse position / 0 + int mh_valid; + int mh_disabled; // T if mouse should be re-enabled. + +public: + tMouHelp() : mh_x(0), mh_y(0), mh_valid(FALSE), mh_disabled(FALSE) {} + ~tMouHelp() + { if(MouseVisible && mh_disabled) DrawMouse(1); + } + + void disIfLine(int x, int w, int y) + { + if(mh_disabled) return; + if(! mh_valid) + { + ConQueryMousePos(&mh_x, &mh_y); + mh_valid = TRUE; + } + if(y == mh_y && mh_x >= x && mh_x < x+y) + { + mh_disabled= TRUE; + DrawMouse(0); + } + } +}; +#endif + +int ConPutBox(int X, int Y, int W, int H, PCell Cell) /*FOLD00*/ +{ + int I; + PCell p = Cell; + COORD corg, csize; + SMALL_RECT rcl; + BOOL rc; + + for (I = 0; I < H; I++) + { + corg.X = corg.Y = 0; + csize.X = W; + csize.Y = 1; + rcl.Left= X; + rcl.Top = I + Y; + rcl.Bottom = I + Y;// + (isWin95 ? 1 : 0); + rcl.Right = X + W - 1;// + (isWin95 ? 1 : 0); + + rc = WriteConsoleOutput(OurConOut, (PCHAR_INFO)p, csize, corg, &rcl); + if (rc != TRUE) { + //("WriteConsoleOutput %d\n", rc); + } + p += W; + } + return 0; +} + +int ConGetBox(int X, int Y, int W, int H, PCell Cell) /*FOLD00*/ +{ + int I; + USHORT WW = W << 1; + PCell p = Cell; + COORD corg, csize; + SMALL_RECT rcl; + + for (I = 0; I < H; I++) + { + corg.X = corg.Y = 0; + csize.X = W; + csize.Y = 1; + rcl.Left = X; + rcl.Top = I + Y; + rcl.Bottom = I + Y;// + (isWin95 ? 1 : 0); + rcl.Right = X + W - 1;// + (isWin95 ? 1 : 0); + + ReadConsoleOutput(OurConOut, (PCHAR_INFO)p, csize, corg, &rcl); + p += W; + } + return 0; +} + +int ConPutLine(int X, int Y, int W, int H, PCell Cell) /*FOLD00*/ +{ + int I; + COORD corg, csize; + SMALL_RECT rcl; + BOOL rc; + + for (I = 0; I < H; I++) + { + corg.X = corg.Y = 0; + csize.X = W; + csize.Y = 1; + rcl.Left = X; + rcl.Top = I + Y; + rcl.Bottom = I + Y;// + (isWin95 ? 1 : 0); + rcl.Right = X + W - 1;// + (isWin95 ? 1 : 0); + + rc = WriteConsoleOutput(OurConOut, (PCHAR_INFO)Cell, csize, corg, &rcl); + if (rc != TRUE) { + //printf("WriteConsoleOutput %d\n", rc); + } + } + return 0; +} + +int ConSetBox(int X, int Y, int W, int H, TCell Cell) /*FOLD00*/ +{ + int I; + COORD corg, csize; + SMALL_RECT rcl; + TDrawBuffer B; + + I = W; + while (I-- > 0) B[I] = Cell; + + for (I = 0; I < H; I++) + { + corg.X = corg.Y = 0; + csize.X = W; + csize.Y = 1; + rcl.Left = X; + rcl.Top = I + Y; + rcl.Bottom = I + Y;// - (isWin95 ? 1 : 0); + rcl.Right = X + W - 1;// - (isWin95 ? 1 : 0); + + WriteConsoleOutput(OurConOut, (PCHAR_INFO)B, csize, corg, &rcl); + } + return 0; +} + +int ConScroll(int Way, int X, int Y, int W, int H, TAttr Fill, int Count) /*FOLD00*/ +{ + TCell FillCell; + SMALL_RECT rect, clip; + COORD dest; + + MoveCh(&FillCell, ' ', Fill, 1); + + clip.Left = X; + clip.Top = Y; + clip.Right = X + W - 1; + clip.Bottom = Y + H - 1; + + rect = clip; + dest.X = X; + dest.Y = Y; + + switch (Way) { + case csUp: + rect.Top += Count; + break; + case csDown: + rect.Bottom -= Count; + dest.Y += Count; + break; + case csLeft: + rect.Left += Count; + break; + case csRight: + rect.Right += Count; + dest.X += Count; + break; + } + + ScrollConsoleScreenBuffer(OurConOut, &rect, &clip, dest, (PCHAR_INFO)&FillCell); + return 0; +} + +int ConSetSize(int X, int Y) { /*FOLD00*/ + return -1; +} + +int ConQuerySize(int *X, int *Y) { /*FOLD00*/ + CONSOLE_SCREEN_BUFFER_INFO csbi; + + GetConsoleScreenBufferInfo(OurConOut, &csbi); + *X = csbi.dwSize.X; + *Y = csbi.dwSize.Y; + + dbg("Console size (%u,%u)\n", *X, *Y); + return 0; +} + +int ConSetCursorPos(int X, int Y) { /*FOLD00*/ + COORD xy; + + xy.X = X; + xy.Y = Y; + SetConsoleCursorPosition(OurConOut, xy); + return 0; +} + +int ConQueryCursorPos(int *X, int *Y) { /*FOLD00*/ + CONSOLE_SCREEN_BUFFER_INFO csbi; + + GetConsoleScreenBufferInfo(OurConOut, &csbi); + *X = csbi.dwCursorPosition.X; + *Y = csbi.dwCursorPosition.Y; + return 0; +} + +int ConShowCursor(void) { /*FOLD00*/ + CursorVisible = 1; + DrawCursor(1); + return 0; +} + +int ConHideCursor(void) { /*FOLD00*/ + CursorVisible = 0; + DrawCursor(0); + return 0; +} + +int ConCursorVisible() { /*FOLD00*/ + return (CursorVisible == 1); +} + +int ConSetCursorSize(int Start, int End) { /*FOLD00*/ + return -1; +} + +int ConSetMousePos(int X, int Y) { /*FOLD00*/ + return -1; +} + +int ConQueryMousePos(int *X, int *Y) { /*FOLD00*/ + *X = LastMouseX; + *Y = LastMouseY; + + // NT does not have this ? (not needed anyway, but check mouse hiding above). + return 0; +} + +int ConShowMouse(void) { /*FOLD00*/ + MouseVisible = 1; + if (!MousePresent) return -1; + return 0; +} + +int ConHideMouse(void) { /*FOLD00*/ + MouseVisible = 0; + if (!MousePresent) return -1; + return 0; +} + +int ConMouseVisible() { /*FOLD00*/ + return (MouseVisible == 1); +} + +int ConQueryMouseButtons(int *ButtonCount) { /*FOLD00*/ + return 0; +} + +int ConPutEvent(TEvent Event) { /*FOLD00*/ + EventBuf = Event; + return 0; +} + +int ConFlush(void) { /*FOLD00*/ + return 0; +} + +int ConGrabEvents(TEventMask EventMask) { /*FOLD00*/ + return 0; +} + + +static PCell SavedScreen = 0; +static int SavedX, SavedY, SaveCursorPosX, SaveCursorPosY; + +int SaveScreen() { /*FOLD00*/ + if (SavedScreen) + free(SavedScreen); + + ConQuerySize(&SavedX, &SavedY); + + SavedScreen = (PCell) malloc(SavedX * SavedY * sizeof(TCell)); + + if (SavedScreen) + ConGetBox(0, 0, SavedX, SavedY, SavedScreen); + ConQueryCursorPos(&SaveCursorPosX, &SaveCursorPosY); + return 0; +} + +int RestoreScreen() { /*FOLD00*/ + if (SavedScreen) { + ConPutBox(0, 0, SavedX, SavedY, SavedScreen); + ConSetCursorPos(SaveCursorPosX, SaveCursorPosY); + } + return 1; +} + + +GUI::GUI(int &argc, char **argv, int XSize, int YSize) { /*FOLD00*/ + fArgc = argc; + fArgv = argv; + ::ConInit(-1, -1); + SaveScreen(); + ::ConSetSize(XSize, YSize); + gui = this; +} + +GUI::~GUI() { /*FOLD00*/ + RestoreScreen(); + + if (SavedScreen) + free(SavedScreen); + + ::ConDone(); + gui = 0; +} + +int GUI::ConSuspend(void) { /*FOLD00*/ + RestoreScreen(); + return ::ConSuspend(); +} + +int GUI::ConContinue(void) { /*FOLD00*/ + SaveScreen(); + return ::ConContinue(); +} + +int GUI::ShowEntryScreen() { /*FOLD00*/ + TEvent E; + + ConHideMouse(); + RestoreScreen(); + SetConsoleActiveScreenBuffer(ConOut); + do { gui->ConGetEvent(evKeyDown, &E, -1, 1, 0); } while (E.What != evKeyDown); + SetConsoleActiveScreenBuffer(OurConOut); + ConShowMouse(); + if (frames) + frames->Repaint(); + return 1; +} + +char ConGetDrawChar(int index) { /*FOLD00*/ + static char tab[] = "Ú¿ÀÙijÂôÁÅ\x1Aúı°\x1B\x1A"; + + assert(index >= 0 && index < (int)strlen(tab)); + + return tab[index]; +} + + +int GUI::RunProgram(int mode, char *Command) { /*FOLD00*/ + int rc, W, H, W1, H1; + + ConQuerySize(&W, &H); + ConHideMouse(); + ConSuspend(); + + if (*Command == 0) // empty string = shell + Command = getenv( + "COMSPEC" + ); + + rc = system(Command); + + ConContinue(); + ConShowMouse(); + ConQuerySize(&W1, &H1); + + if (W != W1 || H != H1) { + frames->Resize(W1, H1); + } + frames->Repaint(); + return rc; +} + +int ConSetTitle(char *Title, char *STitle) { /*FOLD00*/ + return 0; +} + +int ConGetTitle(char *Title, int MaxLen, char *STitle, int SMaxLen) { /*FOLD00*/ + strcpy(Title, "FTE"); + strcpy(STitle, "FTE"); + return 0; +} + + + +#if 0 +/****************************************************************************/ +/* */ +/* CODING: Pipe handler. */ +/* */ +/****************************************************************************/ +/*--------------------------------------------------------------------------*/ +/* STATIC GLOBALS. */ +/*--------------------------------------------------------------------------*/ +#define MAX_PIPES 4 +#define PIPE_BUFLEN 4096 +#define PIPEBUF_SZ 4096 + +class NTHandle +{ +protected: + HANDLE nth_h; + +public: + operator HANDLE() + { return nth_h; + } + + void close() + { if(nth_h != INVALID_HANDLE_VALUE) + { + CloseHandle(nth_h); + nth_h = INVALID_HANDLE_VALUE; + } + } + + + NTHandle() { nth_h = INVALID_HANDLE_VALUE; } + + ~NTHandle() + { close(); + } + + NTHandle(const HANDLE& h) : nth_h(h) {} + NTHandle(const NTHandle& nth); // UNDEFINED (no assgn) + NTHandle& operator =(const NTHandle& nth); // UNDEFINED (no assgn) + NTHandle& operator =(const HANDLE nth) + { close(); + nth_h = nth; + return *this; + } +}; + + +class GPipe +{ +public: + int p_used; + int p_id; + char* p_buffer; + int p_buflen; + int p_bufused; + int p_bufpos; + EModel* p_notify; + char* p_command; + int p_retcode; + int p_doterm; + + //** NT specific. + HANDLE p_proc_h; // Handle of spawned process, + HANDLE pipeDataRead; + HANDLE pipeStartRead; + HANDLE pipeMutex; + HANDLE p_pipe_ph; // Input pipe (read by FTE) + HANDLE p_child_ph; // Client side's handle (written to by spawned) + DWORD p_read_len; // #bytes read in overlapped I/O + int p_io_posted; // T when overlapped I/O is posted, + int p_completed; // T when client process closed down. + int p_has_data; // T when OVERLAPPED completed. + + static GPipe pipe_ar[MAX_PIPES]; + + +public: + int open(char *Command, EModel *notify); + int close(); + int read(void *buffer, int len); + int getEvent(TEvent* event); + + +protected: + int createPipe(); + void releasePipe(); + int runCommand(); + void closeProc(); + int handlePost(); + int postRead(); + + + +public: + static GPipe* getFreePipe(); + static GPipe* getPipe(int id); + +}; + +GPipe GPipe::pipe_ar[MAX_PIPES]; + + +/* + * getFreePipe() locates an unused GPipe structure. It also assigns it's ID. + */ +GPipe* GPipe::getFreePipe() /*FOLD00*/ +{ + int i; + + for(i = 0; i < MAX_PIPES; i++) + { + if(! pipe_ar[i].p_used) + { + pipe_ar[i].p_id = i; // Set pipenr, + return pipe_ar + i; + } + } + return NULL; // No free pipe +} + + +GPipe* GPipe::getPipe(int id) /*FOLD00*/ +{ + if (id < 0 || id > MAX_PIPES) return NULL; + if(! pipe_ar[id].p_used) return NULL; + return pipe_ar + id; +} + + +int GPipe::createPipe() /*FOLD00*/ +{ + /* + * Called from open() to create and open the server and the client pipes. + */ + static int PCount = 0; + //HANDLE hchild; + char pipename[50]; + int ok; + SECURITY_ATTRIBUTES sa; + + sa.nLength = sizeof(sa); // Security descriptor for INHERIT. + sa.lpSecurityDescriptor = 0; + sa.bInheritHandle = 1; + +#if 1 + if (CreatePipe(&p_pipe_ph, &p_child_ph, &sa, 0) == FALSE) + return FALSE; + + Pipes[i].tid = _beginthread(PipeThread, + FAKE_BEGINTHREAD_NULL + 16384, &Pipes[i]); +#else + + //** Create the named pipe, and handle the SERVER (edit)'s end... + sprintf(pipename, "\\\\.\\pipe\\fte%d\\child%d", getpid(), PCount); + p_pipe_ph = CreateNamedPipe(pipename, + PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED, + PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, + 1, // nMaxInstances, + 0, PIPEBUF_SZ, + 1000, + 0); + if(p_pipe_ph == INVALID_HANDLE_VALUE) + return FALSE; + PCount++; + + /* + * Client side: get a connection to the server's pipe. Do this before the + * call to ConnectNamedPipe() to prevent it from blocking. + */ + +#if 1 + p_child_ph = CreateFile(pipename, GENERIC_WRITE, 0, &sa, + OPEN_EXISTING, 0, 0); +#else + p_child_ph = CreateFile("_test", GENERIC_WRITE|GENERIC_READ, 0, &sa, + CREATE_ALWAYS, 0, 0); +#endif + if(p_child_ph == INVALID_HANDLE_VALUE) + dbm("CreateFile(client_side_pipe) has failed"); + else + { + //** Server side: aquire connection.. + ok = TRUE; + if(! ConnectNamedPipe(p_pipe_ph, 0)) // Get connect; + { + if(GetLastError() != ERROR_PIPE_CONNECTED) + ok = FALSE; + } + + //** Connect worked? + if(!ok) + dbm("ConnectNmPipe() has failed"); + else + return TRUE; // All opened & ready for action! + + //** Something went wrong. + CloseHandle(p_child_ph); // Close child: was inh. + DisconnectNamedPipe(p_pipe_ph); // Force disconnection of client (-) + CloseHandle(p_child_ph); + } + CloseHandle(p_pipe_ph); +#endif + return FALSE; // Something has failed. +} + + +void GPipe::releasePipe() /*FOLD00*/ +{ + /* + * releasePipe() releases all that createPipe() allocates. It's usually + * called when an error causes the process to abort. + */ + if(p_child_ph != INVALID_HANDLE_VALUE) + { + CloseHandle(p_child_ph); + p_child_ph = INVALID_HANDLE_VALUE; + } + + if(p_pipe_ph != 0) + { + //DisconnectNamedPipe(p_pipe_ph); + CloseHandle(p_pipe_ph); + p_pipe_ph = INVALID_HANDLE_VALUE; + } +} + + +int GPipe::runCommand() /*FOLD00*/ +{ + /* + * runCommand() takes the child pipe, dups it onto stdout and stderr while + * saving their old assignments, then it spawns + */ + int ok; + char* comspec, *args, tbuf[256]; + HANDLE errh; + PROCESS_INFORMATION pi; + STARTUPINFO si; + const char nt4[] = "4nt.exe"; + + ok = FALSE; + comspec = getenv("COMSPEC"); + + /* + * BUG workaround: When using 4NT, it doesn't properly reassign stderr! + * This is a bug in 4NT, so if comspec *is* 4nt use cmd.exe instead... + */ + if(comspec == 0) return -1; + int l = strlen(comspec); + if(strnicmp(comspec + (l- sizeof(nt4)+1), nt4, sizeof(nt4)-1) == 0) + { + //** It's 4DOS all right.. + args = getenv("SystemRoot"); + if(args== 0) return -1; + strcpy(tbuf, args); // Get to c:\winnt + strcat(tbuf, "\\system32\\cmd.exe"); + comspec = tbuf; + } + + args = (char *)malloc(strlen(comspec) + strlen(p_command) + 120); + if(args == 0) + dbm("malloc() failed for command line.."); + else + { + //** Form a command line for the process; + strcpy(args, comspec); + strcat(args, " /c "); + strcat(args, p_command); + + //** Dup the child handle to get separate handles for stdout and err, + if (DuplicateHandle(GetCurrentProcess(), p_child_ph, // Source, + GetCurrentProcess(), &errh, // Destination, + 0, True, // Same access, inheritable + DUPLICATE_SAME_ACCESS)); + + { + /* Set up members of STARTUPINFO structure. */ + memset(&si, 0, sizeof(si)); + si.cb = sizeof(STARTUPINFO); + si.lpReserved = NULL; + si.lpReserved2 = NULL; + si.cbReserved2 = 0; + si.lpDesktop = NULL; +/* si.dwFlags = STARTF_USESTDHANDLES; +#if 1 + si.hStdOutput = p_child_ph; + si.hStdError = errh; + si.hStdInput = INVALID_HANDLE_VALUE; +#else + si.hStdOutput = errh; + si.hStdError = p_child_ph; + si.hStdInput = INVALID_HANDLE_VALUE; +#endif*/ + if(CreateProcess(NULL, args, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi)) + { + ok = TRUE; + CloseHandle(pi.hThread); // Thread handle not needed + p_proc_h = pi.hProcess; // Return process handle (to get RC) + } + CloseHandle(errh); // Close error handle, + } + else + dbm("DupHandle for stderr failed."); + + free(args); // Release command line. + } + + // SetConsoleMode(horgout, ENABLE_WINDOW_INPUT | ENABLE_MOUSE_INPUT); + + //** And last but not least: close the child handle. + CloseHandle(p_child_ph); + p_child_ph = INVALID_HANDLE_VALUE; + return ok; +} + + +void GPipe::closeProc() /*FOLD00*/ +{ + /* + * closeProc() gets called when a read fails. It assumes the process has + * ended, retrieves the process return code, then it closes all handles. + * The state is set to p_completed. + */ + DWORD ec; + + dbg("[closeProc] "); + + if(! GetExitCodeProcess(p_proc_h, &ec)) ec = 0xabcd; + p_retcode = ec; // Save return code of process, + if(p_proc_h != INVALID_HANDLE_VALUE) // Close process, + { + CloseHandle(p_proc_h); + p_proc_h = INVALID_HANDLE_VALUE; + } + + //** Close the main pipe, + if(p_pipe_ph != INVALID_HANDLE_VALUE) + { + CloseHandle(p_pipe_ph); + p_pipe_ph = INVALID_HANDLE_VALUE; + } + p_completed = TRUE; + p_has_data = TRUE; +} + + +int GPipe::startRead() /*FOLD00*/ +{ + /* + * postRead() checks if an overlapped READ needs to be posted by checking + * the io_posted flag. If that's clear and no termination or closed flag + * is set then a new overlapped I/O request is issued. + */ + p_has_data = FALSE; + dbg("[postRead "); + if(p_io_posted || p_completed) + dbg("no action: %s] ", p_io_posted ? "posted" : "complete"); + else + { + p_ovl.hEvent = p_data_evh; // Signal this when done, + if(!ReadFile(p_pipe_ph, p_buffer, p_buflen, &p_read_len, NULL)) + { + DWORD ec = GetLastError(); + if(ec != ERROR_IO_PENDING) + { + //** Something's wrong. Treat as closed pipe for now. + closeProc(); // Close pipe, complete stuff... + dbg("postfail] "); + return FALSE; // And return failure. + } + } + p_io_posted = TRUE; // Handle pending ioresult. + dbg("posted] "); + } + return TRUE; +} + + +int GPipe::open(char* command, EModel* notify) /*FOLD00*/ +{ + memset(&p_ovl, 0, sizeof(p_ovl)); // Clear overlapped, + p_bufused = 0; + p_bufpos = 0; + p_io_posted = FALSE; + p_has_data = FALSE; + p_completed = FALSE; // T if client closed. + p_doterm = FALSE; + p_buflen = PIPE_BUFLEN; + p_notify = notify; + p_doterm = FALSE; + + p_pipe_ph = INVALID_HANDLE_VALUE; + p_child_ph = INVALID_HANDLE_VALUE; + if( (p_command = strdup(command)) == 0) + return -1; + + //** Allocate the read buffer; + if ((p_buffer = (char*) malloc(p_buflen)) != 0) { + if ((pipeDataRead = CreateEvent(0, 1, 0, 0)) == 0) { + dbm("CreateEvent(data_evh) failed."); + goto fail; + } + if ((pipeStartRead = CreateEvent(0, 1, 0, 0)) == 0) { + dbm("CreateEvent(data_evh) failed."); + goto fail; + } + if ((pipeMutex = CreateMutex(NULL, FALSE, NULL)) == NULL) { + dbm("Failed pipe mutex"); + goto fail; + } + + + else + { + if(createPipe()) // Create server & client pipe. + { + if(! postRead()) + dbm("postRead() initial failed."); + else + { + if(runCommand()) + { + p_used = TRUE; + return p_id; + } + } + releasePipe(); // Release pipes, + } + CloseHandle(p_data_evh); + } + free(p_buffer); + } + free(p_command); + return -1; +} + + +int GPipe::close() /*FOLD00*/ +{ + /* + * close() disconnects from the spawned task, closes the pipe and releases + * all stuff. + */ + if(! p_used) return -1; + if(! p_completed) // Overlapped I/O not complete yet? + { + //** We *must* wait till the overlapped I/O completes, + if(p_io_posted) + { + GetOverlappedResult(p_pipe_ph, &p_ovl, &p_read_len, TRUE); + p_io_posted = FALSE; + } + } + p_completed= TRUE; + + //** Now close all that might be pending, + free(p_buffer); + free(p_command); + + releasePipe(); // Close all pipe stuff, + if(p_proc_h != INVALID_HANDLE_VALUE) + { + CloseHandle(p_proc_h); + p_proc_h = INVALID_HANDLE_VALUE; + } + + CloseHandle(pipeStartRead); + CloseHandle(pipeDataRead); + CloseHandle(pipeMutex); + + p_used = FALSE; + return p_retcode; +} + + +int GPipe::read(void *buffer, int len) /*FOLD00*/ +{ + /* + * read() is called to get the current data from the pipe. It takes the + * #bytes read and returns them. It returns data till the buffer is + * exhausted. If the process is completed it returns -1; else it returns + * the #bytes read. It returns 0 if the buffer's empty. + */ + dbg("[read "); + if(p_has_data) + { + if(p_bufpos < p_read_len) // Data in buffer? + { + unsigned l; + + l = p_read_len - p_bufpos; // Try to output all, + if(l > len) l = len; + memcpy(buffer, p_buffer+p_bufpos, l); // Copy data from the buffer, + p_bufpos += l; + dbg("%u data] ", l); + return l; // Data returned, + } + + //** There's nothing left in the buffer. Is the task complete? + if(p_completed) + { + dbg("no data, complete] "); + return -1; + } + + if(! postRead()) + { + dbg("post failed-> complete] "); + return -1; + } + + dbg("nodata, post] "); + return 0; + } + else if(p_completed) + { + dbg("completed] "); + return -1; + } + + dbg("nothing] "); + return 0; +} + + +int GPipe::getEvent(TEvent* event) /*FOLD00*/ +{ + dbg("[getpipeevent: "); + event->What = evNone; + + if(! p_used || p_notify == 0) return 0; // No data. + if(! handlePost()) return 0; // Again: no data, + //** This pipe has data! + event->What = evNotify; + event->Msg.View = 0; + event->Msg.Model = p_notify; + event->Msg.Command = cmPipeRead; + event->Msg.Param1 = p_id; + dbg("ok] "); + return 1; +} + + +/* + * NT Pipe handler - overview + * ========================== + * The NT pipe handler uses overlapped I/O to read console events. + * + * OpenPipe(): + * When the pipe is opened, one of the pipe structures is allocated and set + * to used. Then an event semaphore (reset_manual) is created. This semaphore + * will be signalled when data is available on the input pipe which gathers + * the spawned tasks's output. + * + * Then a pipe is created, opened for the client side and stdout and stderr + * are redirected therein. After that the client task is spawned. + * + * If the spawn succeeds an overlapped READ is posted for the pipe; then the + * OpenPipe function returns. + * + * ConGetEvent(): + * The ConGetEvent() handler does a WaitForMultipleObjects() on the console + * handle and all pipe handles currently active. If a pipe has data the + * overlapped result is gotten, and the output is sent to the message window. + * Then, if the thread didn't finish, a new overlapped read is posted. + * + * + */ +int GUI::OpenPipe(char *Command, EModel *notify) /*FOLD00*/ +{ + GPipe* gp; + + if( (gp = GPipe::getFreePipe()) == 0) + return -1; // Out of pipes. + return gp->open(Command, notify); // And ask the pipe to init. +} + + +int GUI::SetPipeView(int id, EModel *notify) /*FOLD00*/ +{ + GPipe* p; + + if( (p = GPipe::getPipe(id)) == 0) return -1; + p->lock(); + p->p_notify = notify; + p->unlock(); + return 0; +} + + +int GUI::ReadPipe(int id, void *buffer, int len) /*FOLD00*/ +{ + //int l; + GPipe* p; + + if( (p = GPipe::getPipe(id)) == 0) return -1; + return p->read(buffer, len); +} + + +int GUI::ClosePipe(int id) /*FOLD00*/ +{ + GPipe* p; + + if( (p = GPipe::getPipe(id)) == 0) return -1; + return p->close(); +} + + +static int GetPipeEvent(int id, TEvent *Event) /*FOLD00*/ +{ + //int i; + GPipe* p; + + if( (p = GPipe::getPipe(id)) == 0) return -1; + return p->getEvent(Event); +} + +#else + +#define MAX_PIPES 4 +#define PIPE_BUFLEN 4096 + +typedef struct { + int used; + int id; + int reading, stopped; + HANDLE Thread; + HANDLE Access; + HANDLE ResumeRead; + HANDLE NewData; + char *buffer; + int buflen; + int bufused; + int bufpos; + EModel *notify; + char *Command; + DWORD RetCode; + int DoTerm; +} GPipe; + +static GPipe Pipes[MAX_PIPES] = { + { 0 }, { 0 }, { 0 }, { 0 } +}; + +static int CreatePipeChild(HANDLE &child, HANDLE &hPipe, char *Command) { + static int PCount = 0; + int arglen = 0; + HANDLE hChildPipe; + BOOL rc; + + SECURITY_ATTRIBUTES sa; + + sa.nLength = sizeof(sa); // Security descriptor for INHERIT. + sa.lpSecurityDescriptor = 0; + sa.bInheritHandle = 1; + + rc = CreatePipe(&hPipe, &hChildPipe, &sa, 0); + if (rc != TRUE) + return -1; + + int ok; + char* comspec, *args, tbuf[256]; + //HANDLE errh; + PROCESS_INFORMATION pi; + STARTUPINFO si; + HANDLE hNul; + const char nt4[] = "4nt.exe"; + + ok = FALSE; + comspec = getenv("COMSPEC"); + + /* + * BUG workaround: When using 4NT, it doesn't properly reassign stderr! + * This is a bug in 4NT, so if comspec *is* 4nt use cmd.exe instead... + */ + if (comspec == 0) + return -1; + int l = strlen(comspec); + if (strnicmp(comspec + (l- sizeof(nt4)+1), nt4, sizeof(nt4)-1) == 0) + { + //** It's 4DOS all right.. + args = getenv("SystemRoot"); + if(args== 0) return -1; + strcpy(tbuf, args); // Get to c:\winnt + strcat(tbuf, "\\system32\\cmd.exe"); + comspec = tbuf; + } + + args = (char *)malloc(strlen(comspec) + strlen(Command) + 120); + if(args == 0) + dbm("malloc() failed for command line.."); + else + { + //** Form a command line for the process; + strcpy(args, comspec); + strcat(args, " /c "); + strcat(args, Command); + + //** Dup the child handle to get separate handles for stdout and err, + /*if (DuplicateHandle(GetCurrentProcess(), hChildPipe, + GetCurrentProcess(), &errh, + 0, True, DUPLICATE_SAME_ACCESS))*/ + //fprintf(stderr, "open NUL\n"); + + hNul = CreateFile("NUL", + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, OPEN_EXISTING, + 0, + NULL); + //fprintf(stderr, "starting %s\n", args); + + if (hNul != NULL) { + /* Set up members of STARTUPINFO structure. */ + memset(&si, 0, sizeof(si)); + si.cb = sizeof(STARTUPINFO); + si.lpReserved = NULL; + si.lpReserved2 = NULL; + si.cbReserved2 = 0; + si.lpDesktop = NULL; + si.dwFlags = STARTF_USESTDHANDLES; +#if 1 + si.hStdOutput = hChildPipe; + si.hStdError = hChildPipe; + si.hStdInput = hNul;//INVALID_HANDLE_VALUE; +#else + si.hStdOutput = errh; + si.hStdError = hChildPipe; + si.hStdInput = INVALID_HANDLE_VALUE; +#endif + if (CreateProcess(NULL, args, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi) == TRUE) + { + ok = TRUE; + CloseHandle(pi.hThread); // Thread handle not needed + //fprintf(stderr, "create process success\n"); + child = pi.hProcess; // Return process handle (to get RC) + } else + //fprintf(stderr, "create process failed %d\n" + GetLastError()); + CloseHandle(hNul); // Close error handle, + } + else + dbm("DupHandle for stderr failed."); + + free(args); + } + + CloseHandle(hChildPipe); + return 0; +} + +static DWORD __stdcall PipeThread(void *p) { + GPipe *pipe = (GPipe *)p; + BOOL rc; + DWORD used; + HANDLE child; + HANDLE hfPipe; + + rc = CreatePipeChild(child, hfPipe, pipe->Command); + + if (rc != 0) { + //fprintf(stderr, "Failed CreatePipeChild\n"); + WaitForSingleObject(pipe->Access, INFINITE); + pipe->reading = 0; + SetEvent(pipe->NewData); + ReleaseMutex(pipe->Access); + return 0xFFFFFFFF; + } + + //fprintf(stderr, "Pipe: Begin: %d %s\n", pipe->id, pipe->Command); + while (1) { + //fprintf(stderr, "Waiting on pipe\n"); + rc = ReadFile(hfPipe, pipe->buffer, pipe->buflen, &used, NULL); + if (rc != TRUE) { + //fprintf(stderr, "ReadFile failed %d %ld", GetLastError(), used); + used = 0; + } + + WaitForSingleObject(pipe->Access, INFINITE); + //fprintf(stderr, "Waiting on mutex\n"); + pipe->bufused = used; + //fprintf(stderr, "Pipe: fread: %d %d\n", pipe->id, pipe->bufused); + ResetEvent(pipe->ResumeRead); + if (pipe->bufused == 0) + break; + if (pipe->notify) { + SetEvent(pipe->NewData); + pipe->stopped = 0; + } + ReleaseMutex(pipe->Access); + if (pipe->DoTerm) + break; + //fprintf(stderr, "Waiting on sem\n"); + WaitForSingleObject(pipe->ResumeRead, INFINITE); + //fprintf(stderr, "Read: Released mutex\n"); + if (pipe->DoTerm) + break; + } + CloseHandle(hfPipe); + //fprintf(stderr, "Pipe: pClose: %d\n", pipe->id); + rc = WaitForSingleObject(child, INFINITE); + GetExitCodeProcess(child, &pipe->RetCode); + CloseHandle(child); + pipe->reading = 0; + SetEvent(pipe->NewData); + ReleaseMutex(pipe->Access); + //fprintf(stderr, "Read: Released mutex\n"); + return 0; +} + +int GUI::OpenPipe(char *Command, EModel *notify) { + int i; + + for (i = 0; i < MAX_PIPES; i++) { + if (Pipes[i].used == 0) { + Pipes[i].reading = 1; + Pipes[i].stopped = 1; + Pipes[i].id = i; + Pipes[i].bufused = 0; + Pipes[i].bufpos = 0; + Pipes[i].buflen = PIPE_BUFLEN; + Pipes[i].Command = strdup(Command); + Pipes[i].notify = notify; + Pipes[i].DoTerm = 0; + if ((Pipes[i].buffer = (char *)malloc(PIPE_BUFLEN)) == 0) + return -1; + + if ((Pipes[i].Access = CreateMutex(NULL, FALSE, NULL)) == NULL) { + free(Pipes[i].Command); + free(Pipes[i].buffer); + return -1; + } + + if ((Pipes[i].ResumeRead = CreateEvent(0, 1, 0, 0)) == NULL) { + free(Pipes[i].Command); + free(Pipes[i].buffer); + CloseHandle(Pipes[i].Access); + return -1; + } + + if ((Pipes[i].NewData = CreateEvent(0, 1, 0, 0)) == NULL) { + free(Pipes[i].Command); + free(Pipes[i].buffer); + CloseHandle(Pipes[i].ResumeRead); + CloseHandle(Pipes[i].Access); + return -1; + } + + DWORD tid; + + if ((Pipes[i].Thread = CreateThread(NULL, 32768, + &PipeThread, &Pipes[i], + 0, &tid)) == NULL) + { + free(Pipes[i].Command); + free(Pipes[i].buffer); + CloseHandle(Pipes[i].ResumeRead); + CloseHandle(Pipes[i].Access); + CloseHandle(Pipes[i].NewData); + return -1; + } + Pipes[i].used = 1; + //fprintf(stderr, "Pipe Open: %d\n", i); + return i; + } + } + return -1; +} + +int GUI::SetPipeView(int id, EModel *notify) { + if (id < 0 || id > MAX_PIPES) + return -1; + if (Pipes[id].used == 0) + return -1; + WaitForSingleObject(Pipes[id].Access, INFINITE); + //fprintf(stderr, "Pipe View: %d %08X\n", id, notify); + Pipes[id].notify = notify; + ReleaseMutex(Pipes[id].Access); + return 0; +} + +int GUI::ReadPipe(int id, void *buffer, int len) { + int l; + //ULONG ulPostCount; + + if (id < 0 || id > MAX_PIPES) + return -1; + if (Pipes[id].used == 0) + return -1; + //fprintf(stderr, "Read: Waiting on mutex\n"); + //ConContinue(); + WaitForSingleObject(Pipes[id].Access, INFINITE); + //fprintf(stderr, "Pipe Read: Get %d %d\n", id, len); + if (Pipes[id].bufused - Pipes[id].bufpos > 0) { + l = len; + if (l > Pipes[id].bufused - Pipes[id].bufpos) { + l = Pipes[id].bufused - Pipes[id].bufpos; + } + memcpy(buffer, + Pipes[id].buffer + Pipes[id].bufpos, + l); + Pipes[id].bufpos += l; + if (Pipes[id].bufpos == Pipes[id].bufused) { + Pipes[id].bufused = 0; + Pipes[id].bufpos = 0; + //fprintf(stderr, "Pipe Resume Read: %d\n", id); + Pipes[id].stopped = 1; + //fprintf(stderr, "Read: posting sem\n"); + SetEvent(Pipes[id].ResumeRead); + } + } else if (Pipes[id].reading == 0) + l = -1; + else { + l = 0; +// DosBeep(200, 200); + } + //fprintf(stderr, "Pipe Read: Got %d %d\n", id, l); + ReleaseMutex(Pipes[id].Access); + //fprintf(stderr, "Read: Released mutex\n"); + return l; +} + +int GUI::ClosePipe(int id) { + if (id < 0 || id > MAX_PIPES) + return -1; + if (Pipes[id].used == 0) + return -1; + if (Pipes[id].reading == 1) { + Pipes[id].DoTerm = 1; + SetEvent(Pipes[id].ResumeRead); + WaitForSingleObject(&Pipes[id].Thread, INFINITE); + } + free(Pipes[id].buffer); + free(Pipes[id].Command); + CloseHandle(Pipes[id].NewData); + CloseHandle(Pipes[id].ResumeRead); + CloseHandle(Pipes[id].Access); + CloseHandle(Pipes[id].Thread); + //fprintf(stderr, "Pipe Close: %d\n", id); + Pipes[id].used = 0; + //ConContinue(); + return Pipes[id].RetCode; +} + +int GetPipeEvent(int i, TEvent *Event) { + Event->What = evNone; + if (Pipes[i].used == 0) return 0; + if (Pipes[i].notify == 0) return 0; + ResetEvent(Pipes[i].NewData); + //fprintf(stderr, "Pipe New Data: %d\n", i); + Event->What = evNotify; + Event->Msg.View = 0; + Event->Msg.Model = Pipes[i].notify; + Event->Msg.Command = cmPipeRead; + Event->Msg.Param1 = i; + return 1; +} + +#endif + +int ConGetEvent(TEventMask EventMask, TEvent *Event, int WaitTime, int Delete) /*FOLD00*/ +{ + //** Any saved events left? + if (EventBuf.What != evNone) + { + *Event = EventBuf; + if (Delete) EventBuf.What = evNone; + return 0; + } + if (MouseEv.What != evNone) + { + *Event = MouseEv; + if (Delete) MouseEv.What = evNone; + return 0; + } + + //** Now block and wait for a new event on the console handle and all pipes, + HANDLE o_ar[1 + MAX_PIPES]; + DWORD rc; + int i, nh; + + EventBuf.What = evNone; + Event->What = evNone; + + //** Fill the handle array with all active handles for pipes && console, + o_ar[0] = ConIn; + for(i = 0, nh = 1; i < MAX_PIPES; i++) // For all possible pipes + { + if (Pipes[i].used) + o_ar[nh++] = Pipes[i].NewData; + } + + for(;;) + { + rc = WaitForMultipleObjects(nh, o_ar, FALSE, WaitTime); + if(rc != WAIT_FAILED && (rc >= WAIT_OBJECT_0 && rc < WAIT_OBJECT_0+nh)) + { + i = rc - WAIT_OBJECT_0; // Get item that signalled new data + if(i == 0) // Was console? + { + if(ReadConsoleEvent(Event)) // Get console, + return 0; // And exit if valid, + } + else + { + GetPipeEvent(i - 1, Event); // Read data from pipe. + return 0; + } + } + else + return -1; // Something's wrong! + } +} + +#include "clip.h" + +int GetClipText(ClipData *cd) { + int rc = -1; + cd->fLen = 0; + cd->fChar = NULL; + if (OpenClipboard(NULL)) { + HANDLE hmem; + + if ((hmem = GetClipboardData(CF_TEXT)) != NULL) { + LPVOID data; + + if ((data = GlobalLock(hmem)) != NULL) { + int len = strlen((char *)data); + + cd->fChar = (char *)malloc(len); + if (cd->fChar != NULL) { + cd->fLen = len; + memcpy(cd->fChar, data, len); + rc = 0; + } + GlobalUnlock(hmem); + } + } + CloseClipboard(); + } + return rc; +} + +int PutClipText(ClipData *cd) { + int rc = -1; + if (OpenClipboard(NULL)) { + if (EmptyClipboard()) { + HGLOBAL hmem; + + if ((hmem = GlobalAlloc(GMEM_MOVEABLE, cd->fLen + 1)) != NULL) { + LPVOID data; + + if ((data = GlobalLock(hmem)) != NULL) { + memcpy(data, cd->fChar, cd->fLen); + ((char *)data)[cd->fLen] = 0; + GlobalUnlock(hmem); + if (SetClipboardData(CF_TEXT, hmem)) { + rc = 0; + } + } + } + } + CloseClipboard(); + } + return rc; +} diff --git a/src/con_os2.cpp b/src/con_os2.cpp new file mode 100644 index 0000000..6ab4869 --- /dev/null +++ b/src/con_os2.cpp @@ -0,0 +1,1226 @@ +/* con_os2.cpp + * + * Copyright (c) 1994-1998, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +// include + +#include +#include +#include +#include +#include + +#include "sysdep.h" +#include "console.h" +#include "gui.h" + +extern int ShowVScroll; + +//#define INCL_NOPM +//#define INCL_WINSWITCHLIST +#define INCL_WIN +#define INCL_SUB +#define INCL_KBD +#define INCL_VIO +#define INCL_MOU +#define INCL_BASE +#define INCL_DOS +#define INCL_DOSDEVIOCTL + +#include +#include + +#ifndef OS2_INCLUDED +#include +#endif + +#define MAX_PIPES 4 +#define PIPE_BUFLEN 4096 + +typedef struct { + int used; + int id; + int reading, stopped; + TID tid; + HMTX Access; + HEV ResumeRead; + HEV NewData; + char *buffer; + int buflen; + int bufused; + int bufpos; + EModel *notify; + char *Command; + int RetCode; + int DoTerm; +} GPipe; + +static GPipe Pipes[MAX_PIPES] = { + { 0 }, { 0 }, { 0 }, { 0 } +}; + +static long MouseAutoDelay = 400; +static long MouseAutoRepeat = 5; +static long MouseMultiClick = 300; + +static int Initialized = 0; +static int MousePresent = 0; +static int CursorVisible = 1; /* 1 means visible */ +static int MouseVisible = 0; /* 0 means hidden */ +static TEvent MouseEv = { evNone }; +static TEvent EventBuf = { evNone }; +static HMOU MouseHandle = 0; +static KBDINFO SaveKbdState; + +// misc + +static void DrawCursor(int Show) { + VIOCURSORINFO vci; + VioGetCurType(&vci, 0); + if (Show == 1) + vci.attr = 1; + else + vci.attr = (SHORT)-1; + VioSetCurType(&vci, 0); +} + +static void DrawMouse(int Show) { + if (!MousePresent) return; + if (Show == 1) { + MouDrawPtr(MouseHandle); + } else { + NOPTRRECT npr; + int W, H; + + npr.row = 0; + npr.col = 0; + ConQuerySize(&W, &H); + npr.cCol = (USHORT) (W - 1); + npr.cRow = (USHORT) (H - 1); + MouRemovePtr(&npr, MouseHandle); + } +} + +static struct { // TransCharScan + USHORT CharScan; + TKeyCode KeyCode; +} TransCharScan[] = { + { 0x0100, kbEsc }, { 0x011B, kbEsc }, + { 0x1C0D, kbEnter }, { 0x1C0A, kbEnter }, + { 0x1C00, kbEnter }, { 0xE00D, kbEnter | kfGray }, + { 0xA600, kbEnter | kfGray }, { 0xE00A, kbEnter | kfGray }, + { 0x0E08, kbBackSp }, { 0x0E7F, kbBackSp }, + { 0x0E00, kbBackSp }, { 0x0F09, kbTab }, + { 0x9400, kbTab }, { 0xA500, kbTab }, + { 0x0F00, kbTab }, { 0x4E00, '+' | kfGray }, + { 0x9000, '+' | kfGray }, { 0x4E2B, '+' | kfGray }, + { 0x4A00, '-' | kfGray }, { 0x8E00, '-' | kfGray }, + { 0x4A2D, '-' | kfGray }, { 0x3700, '*' | kfGray }, + { 0x9600, '*' | kfGray }, { 0x372A, '*' | kfGray }, + { 0xE02F, '/' | kfGray }, { 0xA400, '/' | kfGray }, + { 0x9500, '/' | kfGray }, { 0x0300, 0 } +}; + +static struct { // TransScan + int ScanCode; + TKeyCode KeyCode; +} TransScan[] = { + { 0x78, '1' }, { 0x79, '2' }, { 0x7A, '3' }, { 0x7B, '4' }, { 0x7C, '5' }, + { 0x7D, '6' }, { 0x7E, '7' }, { 0x7F, '8' }, { 0x80, '9' }, { 0x81, '0' }, + + { 0x10, 'Q' }, { 0x11, 'W' }, { 0x12, 'E' }, { 0x13, 'R' }, { 0x14, 'T' }, + { 0x15, 'Y' }, { 0x16, 'U' }, { 0x17, 'I' }, { 0x18, 'O' }, { 0x19, 'P' }, + + { 0x1E, 'A' }, { 0x1F, 'S' }, { 0x20, 'D' }, { 0x21, 'F' }, { 0x22, 'G' }, + { 0x23, 'H' }, { 0x24, 'J' }, { 0x25, 'K' }, { 0x26, 'L' }, + + { 0x2C, 'Z' }, { 0x2D, 'X' }, { 0x2E, 'C' }, { 0x2F, 'V' }, { 0x30, 'B' }, + { 0x31, 'N' }, { 0x32, 'M' }, + + { 0x29, '`' }, { 0x82, '-' }, { 0x83, '=' }, { 0x2B, '\\' }, { 0x1A, '[' }, + { 0x1B, ']' }, { 0x27, ';' }, { 0x28, '\'' }, { 0x33, ',' }, { 0x34, '.' }, + { 0x35, '/' }, { 0x37, '*' }, { 0x4E, '+' }, { 0x4A, '-' }, + + { 0x3B, kbF1 }, { 0x3C, kbF2 }, { 0x3D, kbF3 }, + { 0x3E, kbF4 }, { 0x3F, kbF5 }, { 0x40, kbF6 }, + { 0x41, kbF7 }, { 0x42, kbF8 }, { 0x43, kbF9 }, + { 0x44, kbF10 }, { 0x85, kbF11 }, { 0x86, kbF12 }, + + { 0x54, kbF1 }, { 0x55, kbF2 }, { 0x56, kbF3 }, + { 0x57, kbF4 }, { 0x58, kbF5 }, { 0x59, kbF6 }, + { 0x5A, kbF7 }, { 0x5B, kbF8 }, { 0x5C, kbF9 }, + { 0x5D, kbF10 }, { 0x87, kbF11 }, { 0x88, kbF12 }, + + { 0x5E, kbF1 }, { 0x5F, kbF2 }, { 0x60, kbF3 }, + { 0x61, kbF4 }, { 0x62, kbF5 }, { 0x63, kbF6 }, + { 0x64, kbF7 }, { 0x65, kbF8 }, { 0x66, kbF9 }, + { 0x67, kbF10 }, { 0x89, kbF11 }, { 0x8A, kbF12 }, + + { 0x68, kbF1 }, { 0x69, kbF2 }, { 0x6A, kbF3 }, + { 0x6B, kbF4 }, { 0x6C, kbF5 }, { 0x6D, kbF6 }, + { 0x6E, kbF7 }, { 0x6F, kbF8 }, { 0x70, kbF9 }, + { 0x71, kbF10 }, { 0x8B, kbF11 }, { 0x8C, kbF12 }, + + { 0x47, kbHome }, { 0x48, kbUp }, { 0x49, kbPgUp }, + { 0x4B, kbLeft }, { 0x4C, kbCenter}, { 0x4D, kbRight }, + { 0x4F, kbEnd }, { 0x50, kbDown }, { 0x51, kbPgDn }, + { 0x52, kbIns }, { 0x53, kbDel }, + + { 0x77, kbHome }, { 0x8D, kbUp }, { 0x84, kbPgUp }, + { 0x73, kbLeft }, { 0x74, kbRight }, + { 0x75, kbEnd }, { 0x91, kbDown }, { 0x76, kbPgDn }, + { 0x92, kbIns }, { 0x93, kbDel }, + + { 0x97, kbHome | kfGray }, { 0x98, kbUp | kfGray }, { 0x99, kbPgUp | kfGray }, + { 0x9B, kbLeft | kfGray }, { 0x9D, kbRight | kfGray }, + { 0x9F, kbEnd | kfGray }, { 0xA0, kbDown | kfGray }, { 0xA1, kbPgDn | kfGray }, + { 0xA2, kbIns | kfGray }, { 0xA3, kbDel | kfGray } +}; + +int ReadKbdEvent(TEvent *Event, int Wait) { + KBDKEYINFO ki; + UCHAR CharCode, ScanCode; + ULONG KeyCode, KeyFlags; + USHORT CharScan, Flags; + static USHORT PrevFlags = 0; + unsigned int I; + + Event->What = evNone; + KbdCharIn(&ki, IO_NOWAIT, 0); + if (!(ki.fbStatus & 0x40)) return 0; + + Event->What = evKeyDown; + + CharCode = ki.chChar; + ScanCode = ki.chScan; + CharScan = (USHORT)((((USHORT)ScanCode) << 8) | ((USHORT)CharCode)); + Flags = ki.fsState; + KeyCode = 0; + KeyFlags = 0; + +/* printf("Key: %X %X %X %X %X \n", (unsigned long) ki.bNlsShift, (unsigned long) ki.fbStatus, (unsigned long) Flags, (unsigned long) CharCode, (unsigned long) ScanCode);*/ + + if ((Flags & (LEFTSHIFT | RIGHTSHIFT)) != 0) KeyFlags |= kfShift; + if ((Flags & (LEFTCONTROL | RIGHTCONTROL)) != 0) KeyFlags |= kfCtrl; + +/* cpCount = sizeof(cpList);*/ +/* rc = DosQueryCp(sizeof(cpList), cpList, &cpCount); // get active code page*/ + if (CharCode != 0) { + if ((Flags & (LEFTALT)) != 0) KeyFlags |= kfAlt; + } else { + if ((Flags & (LEFTALT | RIGHTALT)) != 0) KeyFlags |= kfAlt; + } +/* if (rc != 0) printf("rc = %d\n", rc);*/ + + if (CharScan == 0) { /* shift/alt/ctrl/caps/scroll/num */ + + } else if (ScanCode == 0) { /* alt numeric */ + KeyCode = CharCode; + KeyFlags |= kfAltXXX; + } else { /* now check special combinations */ + for (I = 0; I < sizeof(TransCharScan)/sizeof(TransCharScan[0]); I++) + if (TransCharScan[I].CharScan == CharScan) { + KeyCode = TransCharScan[I].KeyCode; + break; + } + if (KeyCode == 0) { + if ((CharCode == 0) || (CharCode == 0xE0)) { + if (CharCode == 0xE0) + KeyFlags |= kfGray; + for (I = 0; I < sizeof(TransScan)/sizeof(TransScan[0]); I++) + if (TransScan[I].ScanCode == ScanCode) { + KeyCode = TransScan[I].KeyCode; + break; + } + } else { + if (CharCode < 32) + if (KeyFlags & kfCtrl) + CharCode += 64; + KeyCode = CharCode; + } + } + } + Event->Key.Code = KeyCode | KeyFlags; + PrevFlags = Flags; + return 1; +} + +#define TM_DIFF(x,y) ((long)(((long)(x) < (long)(y)) ? ((long)(y) - (long)(x)) : ((long)(x) - (long)(y)))) + +int ReadMouseEvent(TEvent *Event, ULONG EventMask) { + static unsigned short PrevState = 0; + static unsigned short PrevButtons = 0; + static TEvent LastMouseEvent = { evNone }; + static ULONG LastEventTime = 0; + static ULONG LastClick = 0; + static ULONG LastClickTime = 0; + static ULONG LastClickCount = 0; + MOUEVENTINFO mi; + unsigned short Buttons, State, Btn; + USHORT fWait = MOU_NOWAIT; + MOUQUEINFO mq; + ULONG CurTime; + + DosQuerySysInfo(QSV_MS_COUNT, QSV_MS_COUNT, &CurTime, 4); + + Event->What = evNone; + MouGetNumQueEl(&mq, MouseHandle); + if (mq.cEvents == 0) { + if (LastMouseEvent.What == evMouseAuto && (EventMask & evMouseAuto)) { + if (TM_DIFF(CurTime, LastEventTime) >= MouseAutoRepeat) { + *Event = LastMouseEvent; + DosQuerySysInfo(QSV_MS_COUNT, QSV_MS_COUNT, &LastEventTime, 4); + return 1; + } + } + if ((LastMouseEvent.What == evMouseDown || LastMouseEvent.What == evMouseMove) + && + (LastMouseEvent.Mouse.Buttons) + && (EventMask & evMouseAuto)) + { + if (TM_DIFF(CurTime, LastEventTime) >= MouseAutoDelay) { + LastMouseEvent.What = evMouseAuto; + *Event = LastMouseEvent; + DosQuerySysInfo(QSV_MS_COUNT, QSV_MS_COUNT, &LastEventTime, 4); + return 1; + } + } + return 0; + } + + if (MouReadEventQue(&mi, &fWait, MouseHandle) != 0) return 0; + Event->Mouse.X = mi.col; + Event->Mouse.Y = mi.row; + State = mi.fs; + Btn = Buttons = ((State & (2 | 4))?1:0) | + ((State & (8 | 16))?2:0) | + ((State & (32 | 64))?4:0); + if (Buttons != PrevButtons) { + Buttons ^= PrevButtons; + if (PrevButtons & Buttons) + Event->What = evMouseUp; + else + Event->What = evMouseDown; + } else { + Event->What = evMouseMove; + if (Event->Mouse.X == LastMouseEvent.Mouse.X && + Event->Mouse.Y == LastMouseEvent.Mouse.Y) + return 0; + } + Event->Mouse.Buttons = Buttons; + Event->Mouse.Count = 1; + PrevState = State; + PrevButtons = Btn; + + if (Event->What == evMouseDown) { + if (LastClickCount) { + if (LastClick == Event->Mouse.Buttons) { + if (TM_DIFF(CurTime, LastClickTime) <= MouseMultiClick) { + Event->Mouse.Count = ++LastClickCount; + } else { + LastClickCount = 0; + } + } else { + LastClick = 0; + LastClickCount = 0; + LastClickTime = 0; + } + } + + LastClick = Event->Mouse.Buttons; + if (LastClickCount == 0) + LastClickCount = 1; + DosQuerySysInfo(QSV_MS_COUNT, QSV_MS_COUNT, &LastClickTime, 4); + } +/* if (Event->What == evMouseMove) { + LastClick = 0; + LastClickCount = 0; + LastClickTime = 0; + }*/ + { + KBDINFO ki; + USHORT Flags; + TKeyCode KeyFlags = 0; + + ki.cb = sizeof(ki); + KbdGetStatus(&ki, 0); + Flags = ki.fsState; + + if ((Flags & (LEFTSHIFT | RIGHTSHIFT)) != 0) KeyFlags |= kfShift; + if ((Flags & (LEFTCONTROL | RIGHTCONTROL)) != 0) KeyFlags |= kfCtrl; + if ((Flags & (LEFTALT | RIGHTALT)) != 0) KeyFlags |= kfAlt; + + Event->Mouse.KeyMask = KeyFlags; + } + + LastMouseEvent = *Event; + DosQuerySysInfo(QSV_MS_COUNT, QSV_MS_COUNT, &LastEventTime, 4); + return 1; +} + + +int ConClear() { + int W, H; + TDrawBuffer B; + + MoveChar(B, 0, ConMaxCols, ' ', 0x07, 1); + if ((ConQuerySize(&W, &H) == 0) && + ConSetBox(0, 0, W, H, B[0])) return 0; + return -1; +} + +int ConPutBox(int X, int Y, int W, int H, PCell Cell) { + int I; + int MX, MY; + int MouseHidden = 0; + unsigned char *p = (unsigned char *) Cell; + if (MouseVisible) + ConQueryMousePos(&MX, &MY); + + for (I = 0; I < H; I++) { + if (MouseVisible) + if (Y + I == MY) + if ((MX >= X) && (MX <= X + W)) { + DrawMouse(0); + MouseHidden = 1; + } + VioWrtCellStr((PCH)p, (USHORT)(W << 1), (USHORT)(Y + I), (USHORT)X, 0); + + if (MouseHidden) { + DrawMouse(1); + MouseHidden = 0; + } + p += W << 1; + } + return 0; +} + +int ConGetBox(int X, int Y, int W, int H, PCell Cell) { + int I; + int MX, MY; + int MouseHidden = 0; + USHORT WW = (USHORT)(W << 1); + unsigned char *p = (unsigned char *) Cell; + + if (MouseVisible) + ConQueryMousePos(&MX, &MY); + + for (I = 0; I < H; I++) { + if (MouseVisible) + if (Y + I == MY) + if (MX >= X && MX < X + W) { + DrawMouse(0); + MouseHidden = 1; + } + VioReadCellStr((PCH)p, &WW, (USHORT)(Y + I), (USHORT)X, 0); + + if (MouseHidden) { + DrawMouse(1); + MouseHidden = 0; + } + p += W << 1; + } + return 0; +} + +int ConPutLine(int X, int Y, int W, int H, PCell Cell) { + int I; + int MX, MY; + int MouseHidden = 0; + unsigned char *p = (unsigned char *) Cell; + if (MouseVisible) + ConQueryMousePos(&MX, &MY); + + for (I = 0; I < H; I++) { + if (MouseVisible) + if (Y + I == MY) + if (MX >= X && MX < X + W) { + DrawMouse(0); + MouseHidden = 1; + } + VioWrtCellStr((PCH)p, (USHORT)(W << 1), (USHORT)(Y + I), (USHORT)X, 0); + + if (MouseHidden) { + DrawMouse(1); + MouseHidden = 0; + } + } + return 0; +} + +int ConSetBox(int X, int Y, int W, int H, TCell Cell) { + int I; + int MX, MY; + int MouseHidden = 0; + unsigned char *p = (unsigned char *) &Cell; + if (MouseVisible) + ConQueryMousePos(&MX, &MY); + + for (I = 0; I < H; I++) { + if (MouseVisible) + if (Y + I == MY) + if (MX >= X && MX < X + W) { + DrawMouse(0); + MouseHidden = 1; + } + VioWrtNCell((PCH)p, (USHORT)(W), (USHORT)(Y + I), (USHORT)X, 0); + + if (MouseHidden) { + DrawMouse(1); + MouseHidden = 0; + } + } + return 0; +} + +int ConScroll(int Way, int X, int Y, int W, int H, TAttr Fill, int Count) { + int MX, MY; + int MouseHidden = 0; + TCell FillCell = (TCell)(Fill << 8); + + if (MousePresent && MouseVisible) { + ConQueryMousePos(&MX, &MY); + if (MX >= X && MX < X + W && MY >= Y && MY < Y + H) { + DrawMouse(0); + MouseHidden = 1; + } + } + + switch (Way) { + case csUp: + VioScrollUp((USHORT)Y, (USHORT)X, (USHORT)(Y + H - 1), (USHORT)(X + W - 1), (USHORT)Count, (PBYTE)&FillCell, 0); + break; + case csDown: + VioScrollDn((USHORT)Y, (USHORT)X, (USHORT)(Y + H - 1), (USHORT)(X + W - 1), (USHORT)Count, (PBYTE)&FillCell, 0); + break; + case csLeft: + VioScrollLf((USHORT)Y, (USHORT)X, (USHORT)(Y + H - 1), (USHORT)(X + W - 1), (USHORT)Count, (PBYTE)&FillCell, 0); + break; + case csRight: + VioScrollRt((USHORT)Y, (USHORT)X, (USHORT)(Y + H - 1), (USHORT)(X + W - 1), (USHORT)Count, (PBYTE)&FillCell, 0); + break; + } + if (MouseHidden) + DrawMouse(1); + return 0; +} + +int ConSetSize(int X, int Y) { + VIOMODEINFO vmi; + int rc; + + vmi.cb = sizeof(VIOMODEINFO); + VioGetMode(&vmi, 0); + vmi.col = (USHORT)X; + vmi.row = (USHORT)Y; + vmi.cb = 2 + 1 + 1 + 2 + 2; + rc = VioSetMode(&vmi, 0); + if (rc == 0) return 0; + return -1; +} + +int ConQuerySize(int *X, int *Y) { + VIOMODEINFO vmi; + + vmi.cb = sizeof(VIOMODEINFO); + VioGetMode(&vmi, 0); + if (X) *X = vmi.col; + if (Y) *Y = vmi.row; + return 0; +} + +int ConSetCursorPos(int X, int Y) { + VioSetCurPos((USHORT)Y, (USHORT)X, 0); + return 0; +} + +int ConQueryCursorPos(int *X, int *Y) { + USHORT AX, AY; + + VioGetCurPos(&AY, &AX, 0); + if (X) *X = AX; + if (Y) *Y = AY; + return 0; +} + +int ConShowCursor() { + CursorVisible = 1; + DrawCursor(1); + return 0; +} + +int ConHideCursor() { + CursorVisible = 0; + DrawCursor(0); + return 0; +} + +int ConSetCursorSize(int Start, int End) { + VIOCURSORINFO ci; + + VioGetCurType(&ci, 0); + ci.yStart = -Start; + ci.cEnd = -End; + ci.cx = 0; + VioSetCurType(&ci, 0); + return 0; +} + +int ConSetMousePos(int X, int Y) { + PTRLOC mp; + + if (!MousePresent) return -1; + mp.col = (USHORT)X; + mp.row = (USHORT)Y; + MouSetPtrPos(&mp, MouseHandle); + return 0; +} + +int ConQueryMousePos(int *X, int *Y) { + PTRLOC mp; + + if (!MousePresent) return -1; + MouGetPtrPos(&mp, MouseHandle); + if (X) *X = mp.col; + if (Y) *Y = mp.row; + return 0; +} + +int ConShowMouse() { + MouseVisible = 1; + if (!MousePresent) return -1; + DrawMouse(1); + return 0; +} + +int ConHideMouse() { + MouseVisible = 0; + if (!MousePresent) return -1; + DrawMouse(0); + return 0; +} + +int ConMouseVisible() { + return (MouseVisible == 1); +} + +int ConQueryMouseButtons(int *ButtonCount) { + USHORT Count; + if (MouGetNumButtons(&Count, MouseHandle) != 0) return -1; + if (ButtonCount) *ButtonCount = Count; + return 0; +} + + + +int ConInit(int XSize, int YSize) { + USHORT MevMask = 127; + + if (Initialized) + return 0; + + EventBuf.What = evNone; + MousePresent = (MouOpen(NULL, &MouseHandle) == 0) ?1:0; + + if (MousePresent) + MouSetEventMask(&MevMask, MouseHandle); + + memset(&SaveKbdState, 0, sizeof(SaveKbdState)); + SaveKbdState.cb = sizeof(SaveKbdState); + assert(KbdGetStatus(&SaveKbdState, 0) == 0); + ConContinue(); + + Initialized = 1; + + return 0; +} + +int ConDone() { + return ConSuspend(); +} + +int ConSuspend() { + VIOINTENSITY vi; + static KBDINFO ki; + + vi.cb = 6; + vi.type = 2; + vi.fs = 0; + VioSetState(&vi, 0); + + ki = SaveKbdState; + ki.fsMask &= ~(KEYBOARD_ECHO_OFF | KEYBOARD_BINARY_MODE); + ki.fsMask |= (KEYBOARD_ECHO_ON | KEYBOARD_ASCII_MODE); + assert(0 == KbdSetStatus(&ki, 0)); + + ConHideMouse(); + + signal(SIGBREAK, SIG_DFL); + signal(SIGINT, SIG_DFL); + + return 0; +} + +int ConContinue() { + VIOINTENSITY vi; + static KBDINFO ki; + + signal(SIGBREAK, SIG_IGN); + signal(SIGINT, SIG_IGN); + + ki = SaveKbdState; + ki.fsMask &= ~(KEYBOARD_ECHO_ON | KEYBOARD_ASCII_MODE); + ki.fsMask |= (KEYBOARD_ECHO_OFF | KEYBOARD_BINARY_MODE); + assert(KbdSetStatus (&ki, 0) == 0); + + vi.cb = 6; + vi.type = 2; + vi.fs = 1; + VioSetState(&vi, 0); + ConShowMouse(); + return 0; +} + +int GetPipeEvent(TEvent *Event) { + ULONG ulPostCount; + int i; + + Event->What = evNone; + for (i = 0; i < MAX_PIPES; i++) { + if (Pipes[i].used == 0) continue; + if (Pipes[i].notify == 0) continue; + if (DosResetEventSem(Pipes[i].NewData, &ulPostCount) != 0) + continue; + if (ulPostCount > 0) { + //fprintf(stderr, "Pipe New Data: %d\n", i); + Event->What = evNotify; + Event->Msg.View = 0; + Event->Msg.Model = Pipes[i].notify; + Event->Msg.Command = cmPipeRead; + Event->Msg.Param1 = i; + return 1; + } + } + return 0; +} + +int ConGetEvent(TEventMask EventMask, TEvent *Event, int WaitTime, int Delete) { + KBDINFO ki; + + if (EventBuf.What != evNone) { + *Event = EventBuf; + if (Delete) EventBuf.What = evNone; + return 0; + } + if (MouseEv.What != evNone) { + *Event = MouseEv; + if (Delete) MouseEv.What = evNone; + return 0; + } + EventBuf.What = evNone; + Event->What = evNone; + + ki = SaveKbdState; + ki.fsMask &= ~(KEYBOARD_ECHO_ON | KEYBOARD_ASCII_MODE); + ki.fsMask |= (KEYBOARD_ECHO_OFF | KEYBOARD_BINARY_MODE); + assert(KbdSetStatus (&ki, 0) == 0); + + while ((WaitTime == -1) || (WaitTime >= 0)) { + if ((ReadKbdEvent(Event, WaitTime) == 1) && (EventMask & evKeyboard)) break; + else if (MousePresent && (ReadMouseEvent(Event, EventMask) == 1) && (EventMask & evMouse)) break; + else if (GetPipeEvent(Event) == 1) break; + + if (WaitTime == 0) return -1; + DosSleep(5); + if (WaitTime > 0) { + WaitTime -= 5; + if (WaitTime <= 0) return -1; + } + } + if (Event->What != evNone) { + if (Event->What == evMouseMove) { + while (ReadMouseEvent(&MouseEv, EventMask) == 1) { + if (MouseEv.What == evMouseMove) { + *Event = MouseEv; + MouseEv.What = evNone; + } else break; + } + } + EventBuf = *Event; + if (Delete) EventBuf.What = evNone; + return 0; + } + return -1; +} + +static PCell SavedScreen = 0; +static int SavedX, SavedY, SaveCursorPosX, SaveCursorPosY; + +int SaveScreen() { + if (SavedScreen) + free(SavedScreen); + + ConQuerySize(&SavedX, &SavedY); + + SavedScreen = (PCell) malloc(SavedX * SavedY * sizeof(PCell)); + + if (SavedScreen) + ConGetBox(0, 0, SavedX, SavedY, SavedScreen); + ConQueryCursorPos(&SaveCursorPosX, &SaveCursorPosY); + return 0; +} + +int RestoreScreen() { + if (SavedScreen) { + ConPutBox(0, 0, SavedX, SavedY, SavedScreen); + ConSetCursorPos(SaveCursorPosX, SaveCursorPosY); + } + return 1; +} + +GUI::GUI(int &argc, char **argv, int XSize, int YSize) { + fArgc = argc; + fArgv = argv; + ::ConInit(-1, -1); + SaveScreen(); + ::ConSetSize(XSize, YSize); + gui = this; +} + +GUI::~GUI() { + RestoreScreen(); + + if (SavedScreen) + free(SavedScreen); + + ::ConDone(); + gui = 0; +} + +int GUI::ConSuspend(void) { + RestoreScreen(); + return ::ConSuspend(); +} + +int GUI::ConContinue(void) { + SaveScreen(); + return ::ConContinue(); +} + +int GUI::ShowEntryScreen() { + TEvent E; + + ConHideMouse(); + RestoreScreen(); + do { gui->ConGetEvent(evKeyDown, &E, -1, 1, 0); } while (E.What != evKeyDown); + ConShowMouse(); + if (frames) + frames->Repaint(); + return 1; +} + +static int CreatePipeChild(PID &pid, HPIPE &hfPipe, char *Command) { + static int PCount = 0; + char szPipe[32]; + char FailBuf[256]; + char *Args; + int arglen = 0; + char *Prog; + RESULTCODES rc_code; + ULONG ulAction; + //ULONG ulNew; + HPIPE hfChildPipe; + HFILE hfNewStdOut = (HFILE)-1, hfNewStdErr = (HFILE)-1; + HFILE hfStdOut = 1, hfStdErr = 2; + int rc; + + sprintf(szPipe, "\\PIPE\\FTE%d\\CHILD%d", getpid(), PCount); + PCount++; + + rc = DosCreateNPipe(szPipe, &hfPipe, + NP_NOINHERIT | NP_ACCESS_INBOUND, + NP_NOWAIT | NP_TYPE_BYTE | NP_READMODE_BYTE | 1, + 0, 4096, 0); + if (rc != 0) + return -1; + + rc = DosConnectNPipe (hfPipe); + if (rc != 0 && rc != ERROR_PIPE_NOT_CONNECTED) { + DosClose(hfPipe); + return -1; + } + + rc = DosSetNPHState (hfPipe, NP_WAIT | NP_READMODE_BYTE); + if (rc != 0) { + DosClose(hfPipe); + return -1; + } + + rc = DosOpen (szPipe, &hfChildPipe, &ulAction, 0, + FILE_NORMAL, + OPEN_ACTION_OPEN_IF_EXISTS | OPEN_ACTION_FAIL_IF_NEW, + OPEN_ACCESS_WRITEONLY | OPEN_SHARE_DENYREADWRITE, + NULL); + if (rc != 0) { + DosClose (hfPipe); + return -1; + } + + // Duplicate handles + DosDupHandle(hfStdOut, &hfNewStdOut); + DosDupHandle(hfStdErr, &hfNewStdErr); + // Close existing handles for current process + DosClose(hfStdOut); + DosClose(hfStdErr); + // Redirect existing handles to new file + DosDupHandle(hfChildPipe, &hfStdOut); + DosDupHandle(hfChildPipe, &hfStdErr); + // Let started program inherit handles from parent + + Prog = getenv("COMSPEC"); + + Args = (char *)malloc(strlen(Prog) + 1 + + 3 + strlen(Command) + 1 + + 1); + if (Args == NULL) { + DosClose(hfPipe); + return -1; + } + + strcpy(Args, Prog); + arglen = strlen(Args) + 1; + strcpy(Args + arglen, "/c "); + arglen += 3; + strcpy(Args + arglen, Command); + arglen += strlen(Command) + 1; + Args[arglen] = '\0'; + + rc = DosExecPgm(FailBuf, sizeof(FailBuf), + EXEC_ASYNCRESULT, // | EXEC_BACKGROUND, + Args, + 0, + &rc_code, + Prog); + + free(Args); + + // Get back original handles + DosDupHandle(hfNewStdOut, &hfStdOut); + DosDupHandle(hfNewStdErr, &hfStdErr); + // Close the duplicated handles - no longer needed + DosClose(hfNewStdOut); + DosClose(hfNewStdErr); + + DosClose(hfChildPipe); // pipe one way, close out write end + + if (rc != 0) { + DosClose(hfPipe); + return -1; + } + + pid = rc_code.codeTerminate; // get pid when successful + + return 0; +} + +static void _LNK_CONV PipeThread(void *p) { + GPipe *pipe = (GPipe *)p; + int rc; + ULONG ulPostCount; + ULONG used; + PID pid; + HPIPE hfPipe; + RESULTCODES rc_code; + + rc = CreatePipeChild(pid, hfPipe, pipe->Command); + + if (rc != 0) { + //fprintf(stderr, "Failed createpipe"); + DosRequestMutexSem(pipe->Access, SEM_INDEFINITE_WAIT); + pipe->reading = 0; + DosPostEventSem(pipe->NewData); + DosReleaseMutexSem(pipe->Access); + return; + } + + //fprintf(stderr, "Pipe: Begin: %d %s\n", pipe->id, Args); + while (1) { + //fprintf(stderr, "Waiting on pipe\n"); + //fread(pipe->buffer, 1, pipe->buflen, fp); + rc = DosRead(hfPipe, pipe->buffer, pipe->buflen, &used); + if (rc < 0) + used = 0; + + DosRequestMutexSem(pipe->Access, SEM_INDEFINITE_WAIT); + //fprintf(stderr, "Waiting on mutex\n"); + pipe->bufused = used; + //fprintf(stderr, "Pipe: fread: %d %d\n", pipe->id, pipe->bufused); + DosResetEventSem(pipe->ResumeRead, &ulPostCount); + if (pipe->bufused == 0) + break; + if (pipe->notify) { + DosPostEventSem(pipe->NewData); + pipe->stopped = 0; + } + DosReleaseMutexSem(pipe->Access); + if (pipe->DoTerm) + break; + //fprintf(stderr, "Waiting on sem\n"); + DosWaitEventSem(pipe->ResumeRead, SEM_INDEFINITE_WAIT); + //fprintf(stderr, "Read: Released mutex\n"); + if (pipe->DoTerm) + break; + } + DosClose(hfPipe); + //fprintf(stderr, "Pipe: pClose: %d\n", pipe->id); + rc = DosWaitChild(DCWA_PROCESS, DCWW_WAIT, + &rc_code, + &pid, + pid); + pipe->RetCode = rc_code.codeResult; + // pclose(fp); + pipe->reading = 0; + DosPostEventSem(pipe->NewData); + DosReleaseMutexSem(pipe->Access); + //fprintf(stderr, "Read: Released mutex\n"); + return; +} + +int GUI::OpenPipe(char *Command, EModel *notify) { + int i; + + for (i = 0; i < MAX_PIPES; i++) { + if (Pipes[i].used == 0) { + Pipes[i].reading = 1; + Pipes[i].stopped = 1; + Pipes[i].id = i; + Pipes[i].bufused = 0; + Pipes[i].bufpos = 0; + Pipes[i].buflen = PIPE_BUFLEN; + Pipes[i].Command = strdup(Command); + Pipes[i].notify = notify; + Pipes[i].DoTerm = 0; + if ((Pipes[i].buffer = (char *)malloc(PIPE_BUFLEN)) == 0) + { + free(Pipes[i].Command); + return -1; + } + + if (0 != DosCreateMutexSem(0, &Pipes[i].Access, 0, 0)) { + free(Pipes[i].Command); + free(Pipes[i].buffer); + return -1; + } + + if (0 != DosCreateEventSem(0, &Pipes[i].ResumeRead, 0, 0)) { + free(Pipes[i].Command); + free(Pipes[i].buffer); + DosCloseMutexSem(Pipes[i].Access); + return -1; + } + + if (0 != DosCreateEventSem(0, &Pipes[i].NewData, 0, 0)) { + free(Pipes[i].Command); + free(Pipes[i].buffer); + DosCloseEventSem(Pipes[i].ResumeRead); + DosCloseMutexSem(Pipes[i].Access); + return -1; + } + +#if defined(__MT__) || defined(__MULTI__) + Pipes[i].tid = _beginthread(PipeThread, + FAKE_BEGINTHREAD_NULL + 16384, &Pipes[i]); +#else + DosCreateThread(Pipes[i].tid, + (PFNTHREAD)PipeThread, + &Pipes[i], + 0, /* immediate */ + 16384); +#endif + Pipes[i].used = 1; + //fprintf(stderr, "Pipe Open: %d\n", i); + return i; + } + } + return -1; +} + +int GUI::SetPipeView(int id, EModel *notify) { + if (id < 0 || id > MAX_PIPES) + return -1; + if (Pipes[id].used == 0) + return -1; + DosRequestMutexSem(Pipes[id].Access, SEM_INDEFINITE_WAIT); + //fprintf(stderr, "Pipe View: %d %08X\n", id, notify); + Pipes[id].notify = notify; + DosReleaseMutexSem(Pipes[id].Access); + return 0; +} + +int GUI::ReadPipe(int id, void *buffer, int len) { + int l; + //ULONG ulPostCount; + + if (id < 0 || id > MAX_PIPES) + return -1; + if (Pipes[id].used == 0) + return -1; + //fprintf(stderr, "Read: Waiting on mutex\n"); + //ConContinue(); + DosRequestMutexSem(Pipes[id].Access, SEM_INDEFINITE_WAIT); + //fprintf(stderr, "Pipe Read: Get %d %d\n", id, len); + if (Pipes[id].bufused - Pipes[id].bufpos > 0) { + l = len; + if (l > Pipes[id].bufused - Pipes[id].bufpos) { + l = Pipes[id].bufused - Pipes[id].bufpos; + } + memcpy(buffer, + Pipes[id].buffer + Pipes[id].bufpos, + l); + Pipes[id].bufpos += l; + if (Pipes[id].bufpos == Pipes[id].bufused) { + Pipes[id].bufused = 0; + Pipes[id].bufpos = 0; + //fprintf(stderr, "Pipe Resume Read: %d\n", id); + Pipes[id].stopped = 1; + //fprintf(stderr, "Read: posting sem\n"); + DosPostEventSem(Pipes[id].ResumeRead); + } + } else if (Pipes[id].reading == 0) + l = -1; + else { + l = 0; +// DosBeep(200, 200); + } + //fprintf(stderr, "Pipe Read: Got %d %d\n", id, l); + DosReleaseMutexSem(Pipes[id].Access); + //fprintf(stderr, "Read: Released mutex\n"); + return l; +} + +int GUI::ClosePipe(int id) { + if (id < 0 || id > MAX_PIPES) + return -1; + if (Pipes[id].used == 0) + return -1; + if (Pipes[id].reading == 1) { + Pipes[id].DoTerm = 1; + DosPostEventSem(Pipes[id].ResumeRead); + DosWaitThread(&Pipes[id].tid, DCWW_WAIT); + } + free(Pipes[id].buffer); + free(Pipes[id].Command); + DosCloseEventSem(Pipes[id].NewData); + DosCloseEventSem(Pipes[id].ResumeRead); + DosCloseMutexSem(Pipes[id].Access); +// fprintf(stderr, "Pipe Close: %d\n", id); + Pipes[id].used = 0; + //ConContinue(); + return Pipes[id].RetCode; +} + +int GUI::RunProgram(int mode, char *Command) { + int rc, W, H, W1, H1; + + ConQuerySize(&W, &H); + ConHideMouse(); + ConSuspend(); + + if (Command == 0 || *Command == 0) // empty string = shell + Command = getenv( + "COMSPEC" + ); + + rc = system(Command); + + ConContinue(); + ConShowMouse(); + ConQuerySize(&W1, &H1); + + if (W != W1 || H != H1) { + frames->Resize(W1, H1); + } + frames->Repaint(); + return rc; +} + +int ConSetTitle(char *Title, char *STitle) { +/* HSWITCH hsw; + SWCNTRL sw; + HAB hab; + PID pid; + TID tid; + + static PVOID Shmem = NULL; + + if (Shmem == NULL) + DosAllocSharedMem(&Shmem, NULL, 4096, + PAG_COMMIT | PAG_READ | PAG_WRITE | OBJ_GIVEABLE); + + strcpy(Shmem, Title); + + hab = WinInitialize(0); + + hsw = WinQuerySwitchHandle(NULLHANDLE, getpid()); + + if (WinQuerySwitchEntry(hsw, &sw) != 0) + printf("\x7\n"); + else { + + strncpy (sw.szSwtitle, Title, MAXNAMEL - 1); + sw.szSwtitle[MAXNAMEL-1] = 0; + + printf("hwnd: %X, hwndIcon: %X, pid: %d\n", + sw.hwnd, + sw.hwndIcon, + sw.idProcess); + + WinQueryWindowProcess(sw.hwnd, &pid, &tid); + + DosGiveSharedMem(Shmem, pid, PAG_READ | PAG_WRITE); + + printf("txt 1: %d\n", WinSetWindowText(sw.hwnd, Shmem)); +// printf("txt 2: %d\n", WinSetWindowText(Wsw.hwndIcon, Shmem)); + + WinChangeSwitchEntry(hsw, &sw); + } + + WinTerminate(hab); + */ + return 0; +} + +int ConGetTitle(char *Title, int MaxLen, char *STitle, int SMaxLen) { + strcpy(Title, "FTE"); + strcpy(STitle, "FTE"); + return 0; +} + +int ConCursorVisible() { + return (CursorVisible == 1); +} + +int ConPutEvent(TEvent Event) { + EventBuf = Event; + return 0; +} + +extern int SevenBit; + +char ConGetDrawChar(int index) { + static char tab[] = "Ú¿ÀÙijÂôÁÅ\x1Aúı°\x1B\x1A"; + static char tab7[] = "++++-|+++++\x1A.-++#+\x1B\x1A"; + + assert(index >= 0 && index < (int)strlen(tab)); + + if (SevenBit) + return tab7[index]; + else + return tab[index]; +} diff --git a/src/con_slang.cpp b/src/con_slang.cpp new file mode 100644 index 0000000..eb4f284 --- /dev/null +++ b/src/con_slang.cpp @@ -0,0 +1,1057 @@ +/* con_slang.cpp + * + * Copyright (c) 1998, István Váradi + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +int use_esc_hack = 0; + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include "console.h" +// #include "slangkbd.h" +#include "gui.h" + +#define MAX_PIPES 4 +//#define PIPE_BUFLEN 4096 + +typedef struct { + int used; + int id; + int fd; + int pid; + int stopped; + EModel *notify; +} GPipe; + +static GPipe Pipes[MAX_PIPES] = +{ + {0}, + {0}, + {0}, + {0} +}; + +/* These characters cannot appear on a console, so we can detect + * them in the output routine. + */ +#define DCH_SLANG_C1 128 +#define DCH_SLANG_C2 129 +#define DCH_SLANG_C3 130 +#define DCH_SLANG_C4 131 +#define DCH_SLANG_H 132 +#define DCH_SLANG_V 133 +#define DCH_SLANG_M1 134 +#define DCH_SLANG_M2 135 +#define DCH_SLANG_M3 136 +#define DCH_SLANG_M4 137 +#define DCH_SLANG_X 138 +#define DCH_SLANG_RPTR 139 +#define DCH_SLANG_EOL 140 +#define DCH_SLANG_EOF 141 +#define DCH_SLANG_END 142 +#define DCH_SLANG_AUP 143 +#define DCH_SLANG_ADOWN 144 +#define DCH_SLANG_HFORE 145 +#define DCH_SLANG_HBACK 146 +#define DCH_SLANG_ALEFT 147 +#define DCH_SLANG_ARIGHT 148 + +static char slang_dchs[] = +{ + 'l', + 'k', + 'm', + 'j', + 'q', + 'x', + 'f', + 'f', + 'f', + 'f', + 'f', + '+', + '~', + '`', + 'q', + '-', + '.', + ' ', + 'a', + ',', + '+' +}; + +static char raw_dchs[sizeof(slang_dchs)]; + +unsigned char ftesl_get_dch(char raw) +{ + for (int i = 0; i < (int) sizeof(slang_dchs); i++) + if (raw_dchs[i] == raw) + return DCH_SLANG_C1 + i; + return DCH_SLANG_EOL; +} + +static const char *slang_colors[] = +{ + "black", + "blue", + "green", + "cyan", + "red", + "magenta", + "brown", + "lightgray", + "gray", + "brightblue", + "brightgreen", + "brightcyan", + "brightred", + "brightmagenta", + "yellow", + "white", +}; + +/* + * Definitions for keyboard handling under SLang. + */ + +#define FTESL_KEY 0x00001000 // A key defined by me +#define FTESL_KEY_SHIFT 0x00002000 // Key with Shift +#define FTESL_KEY_CTRL 0x00004000 // Key with Ctrl +#define FTESL_KEY_ALT 0x00008000 // Key with Alt +#define FTESL_KEY_GRAY 0x00010000 // Gray Key + +#define FTESL_KEY_ENTER 13 +#define FTESL_KEY_TAB 9 +#define FTESL_KEY_ESC 27 +#define FTESL_KEY_BACKSP 8 + +#define FTESL_KEY_CTRLAND(x) (x+1-'a') + +static TKeyCode speckeys[] = +{ + kbF1, + kbF2, + kbF3, + kbF4, + kbF5, + kbF6, + kbF7, + kbF8, + kbF9, + kbF10, + kbF11, + kbF12, + kbHome, + kbEnd, + kbPgUp, + kbPgDn, + kbIns, + kbDel, + kbUp, + kbDown, + kbLeft, + kbRight, + kbEnter, + kbEsc, + kbBackSp, + kbSpace, + kbTab, + kbCenter, +}; + +/* +static int ftesl_getkeysym(TKeyCode keycode) +{ + unsigned key = keyCode(keycode); + int ksym = -1; + + for (unsigned i = 0; i < sizeof(speckeys) / sizeof(TKeyCode); i++) { + if (key == speckeys[i]) { + ksym = (int) i; + break; + } + } + + if (ksym < 0 && key < 256) { + ksym = (int) key; + } + + if (ksym < 0) + return ksym; + + if (keycode & kfAlt) + ksym |= FTESL_KEY_ALT; + if (keycode & kfCtrl) + ksym |= FTESL_KEY_CTRL; + if (keycode & kfShift) + ksym |= FTESL_KEY_SHIFT; + if (keycode & kfGray) + ksym |= FTESL_KEY_GRAY; + + ksym |= FTESL_KEY; + return ksym; +} +*/ + +int ConInit(int /*XSize */ , int /*YSize */ ) +{ + unsigned i; + unsigned short linebuf[sizeof(slang_dchs)]; + + SLtt_get_terminfo(); + + if (SLkp_init() == -1) { + return -1; + } + if (SLang_init_tty(0, 1, 1) == -1) { + return -1; + } + + if (SLsmg_init_smg() == -1) { + SLang_reset_tty(); + return -1; + } + + SLang_set_abort_signal(NULL); + + SLtty_set_suspend_state(0); + + for (i = 0; i < 128; i++) { + SLtt_set_color(i, NULL, (char *) slang_colors[i & 0x0f], + (char *) slang_colors[((i >> 4) + 0) & 0x07]); + } + + SLsmg_gotorc(0, 0); + SLsmg_set_char_set(1); + + SLsmg_write_nchars(slang_dchs, sizeof(slang_dchs)); + + SLsmg_gotorc(0, 0); + SLsmg_read_raw(linebuf, sizeof(slang_dchs)); + for (i = 0; i < sizeof(slang_dchs); i++) + raw_dchs[i] = (linebuf[i]) & 0xff; + + SLsmg_set_char_set(0); + + use_esc_hack = (getenv("FTESL_ESC_HACK") != NULL); + + return 0; +} +int ConDone(void) +{ + SLsmg_reset_smg(); + SLang_reset_tty(); + return 0; +} + +int ConSuspend(void) +{ + SLsmg_suspend_smg(); + SLang_reset_tty(); + return 0; +} +int ConContinue(void) +{ + SLang_init_tty(-1, 0, 1); + SLsmg_resume_smg(); + return 0; +} + +int ConSetTitle(char * /*Title */ , char * /*STitle */ ) +{ + return 0; +} + +int ConGetTitle(char *Title, int /*MaxLen */ + , char * /*STitle */ , int /*SMaxLen */ ) +{ + *Title = '\0'; + return 0; +} + +int ConClear() +{ + SLsmg_cls(); + SLsmg_refresh(); + return 0; +} + +static void fte_write_color_chars(PCell Cell, int W) +{ + int i = 0; + int chset = 0, chsetprev = 0; + unsigned char ch, col = 0x70, colprev = 0x70; + char buf[256]; + + SLsmg_set_color(colprev); + while (W > 0) { + for (i = 0; i < W && i < (int) sizeof(buf); i++) { + ch = Cell[i] & 0xff; + col = (Cell[i] >> 8) & 0x7f; + if (ch <= 127 || ch >= 0xa0) { + if (ch < 32) + buf[i] = '.'; + else + buf[i] = ch; + chset = 0; + } else { + buf[i] = slang_dchs[ch - 128]; + chset = 1; + } + + + + if (col != colprev || chset != chsetprev) + break; + + } + + if (i > 0) { + SLsmg_write_nchars(buf, i); + W -= i; + Cell += i; + } + + if (col != colprev) { + SLsmg_set_color(col); + colprev = col; + } + + if (chset != chsetprev) { + SLsmg_set_char_set(chset); + chsetprev = chset; + } + } + SLsmg_set_char_set(0); +} + +int ConPutBox(int X, int Y, int W, int H, PCell Cell) +{ + int CurX, CurY; + + ConQueryCursorPos(&CurX, &CurY); + while (H > 0) { + SLsmg_gotorc(Y++, X); + fte_write_color_chars(Cell, W); + Cell += W; + H--; + } + ConSetCursorPos(CurX, CurY); + SLsmg_refresh(); + + return 0; +} + +int ConPutBoxRaw(int X, int Y, int W, int H, unsigned short *box) +{ + int CurX, CurY; + + ConQueryCursorPos(&CurX, &CurY); + while (H > 0) { + SLsmg_gotorc(Y++, X); + SLsmg_write_raw(box, W); + box += W; + H--; + } + ConSetCursorPos(CurX, CurY); + + return 0; + +} + +int ConGetBox(int X, int Y, int W, int H, PCell Cell) +{ + int CurX, CurY, i; + char ch; + + ConQueryCursorPos(&CurX, &CurY); + while (H > 0) { + SLsmg_gotorc(Y++, X); + SLsmg_read_raw(Cell, W); + for (i = 0; i < W; i++) + if (Cell[i] & 0x8000) { + ch = Cell[i] & 0xff; + Cell[i] &= 0x7f00; + Cell[i] |= ftesl_get_dch(ch); + } + Cell += W; + H--; + } + ConSetCursorPos(CurX, CurY); + + return 0; + +} + +int ConGetBoxRaw(int X, int Y, int W, int H, unsigned short *box) +{ + int CurX, CurY; + + ConQueryCursorPos(&CurX, &CurY); + while (H > 0) { + SLsmg_gotorc(Y++, X); + SLsmg_read_raw(box, W); + box += W; + H--; + } + ConSetCursorPos(CurX, CurY); + + return 0; + +} + +int ConPutLine(int X, int Y, int W, int H, PCell Cell) +{ + int CurX, CurY; + + ConQueryCursorPos(&CurX, &CurY); + while (H > 0) { + SLsmg_gotorc(Y, X); + fte_write_color_chars(Cell, W); + H--; + } + ConSetCursorPos(CurX, CurY); + SLsmg_refresh(); + + return 0; +} + +int ConSetBox(int X, int Y, int W, int H, TCell Cell) +{ + PCell line = (PCell) malloc(sizeof(TCell) * W); + int i; + + for (i = 0; i < W; i++) + line[i] = Cell; + ConPutLine(X, Y++, W, H, line); + free(line); + return 0; +} + + + +int ConScroll(int Way, int X, int Y, int W, int H, TAttr Fill, int Count) +{ + unsigned short *box; + + box = new unsigned short [W * H]; + + TCell fill = (((unsigned) Fill) << 8) | ' '; + + ConGetBoxRaw(X, Y, W, H, box); + + if (Way == csUp) { + ConPutBoxRaw(X, Y, W, H - Count, box + W * Count); + ConSetBox(X, Y + H - Count, W, Count, fill); + } else { + ConPutBoxRaw(X, Y + Count, W, H - Count, box); + ConSetBox(X, Y, W, Count, fill); + } + + delete(box); + + return 0; +} + +int ConSetSize(int /*X */ , int /*Y */ ) +{ + return -1; +} + +int ConQuerySize(int *X, int *Y) +{ + *X = SLtt_Screen_Cols; + *Y = SLtt_Screen_Rows; + return 0; +} + +int ConSetCursorPos(int X, int Y) +{ + SLsmg_gotorc(Y, X); + SLsmg_refresh(); + return 0; +} + +int ConQueryCursorPos(int *X, int *Y) +{ + *X = SLsmg_get_column(); + *Y = SLsmg_get_row(); + return 0; +} + +int CurVis = 1; + +int ConShowCursor() +{ + CurVis = 1; + SLtt_set_cursor_visibility(1); + return 0; +} +int ConHideCursor() +{ + CurVis = 0; + SLtt_set_cursor_visibility(0); + return 0; +} +int ConCursorVisible() +{ + return CurVis; +} + +int ConSetCursorSize(int /*Start */ , int /*End */ ) +{ + return 0; +} + +int ConSetMousePos(int /*X */ , int /*Y */ ) +{ + return -1; +} +int ConQueryMousePos(int *X, int *Y) +{ + *X = 0; + *Y = 0; + return 0; +} + +int ConShowMouse() +{ + return -1; +} + +int ConHideMouse() +{ + return -1; +} + +int ConMouseVisible() +{ + return 0; +} + +int ConQueryMouseButtons(int *ButtonCount) +{ + *ButtonCount = 0; + return 0; +} + +static TEvent Prev = +{evNone}; + +static TKeyCode keys_ctrlhack[] = +{ + kfAlt, + kbHome, + kfCtrl, + kbDown, + kbEnd, + + kbF1, + kfCtrl | 'G', + kbBackSp, + kbTab, + kfCtrl | 'J', + + kfCtrl | 'K', + kbLeft, + kbEnter, + kbPgDn, + kfCtrl | 'O', + + kbPgUp, + kbIns, + kbRight, + kfShift, + kfCtrl | 'T', + + kbUp, + kfCtrl | 'V', + kfCtrl | 'W', + kbCenter, + kfCtrl | 'Y', + + kbDel, +}; + +static TKeyCode ftesl_getftekey(unsigned char key) +{ + if (key < 32) + return speckeys[key]; + else + return (TKeyCode) key; +} + +/* + * Keyboard handling with SLang. + */ +static TKeyCode ftesl_process_key(int key, int ctrlhack = 0) +{ + TKeyCode kcode; + + //fprintf(stderr, "KEY %03d \n", key); + if (key < 256 && key >= 32) { + return (TKeyCode) key; + } else if (key >= 1 && key <= 26 && key != 13 && key != 9 && key != 8) { + if (!ctrlhack) + return ((key + 'A' - 1) & 0xff) | kfCtrl; + else + return keys_ctrlhack[key - 1]; + } else if (key & FTESL_KEY) { + kcode = ftesl_getftekey(key & 0x00ff); + if (key & FTESL_KEY_SHIFT) + kcode |= kfShift; + if (key & FTESL_KEY_CTRL) + kcode |= kfCtrl; + if (key & FTESL_KEY_ALT) + kcode |= kfAlt; + if (key & FTESL_KEY_GRAY) + kcode |= kfGray; + return kcode; + } else + switch (key) { + case SL_KEY_UP: + return kbUp; + case SL_KEY_DOWN: + return kbDown; + case SL_KEY_LEFT: + return kbLeft; + case SL_KEY_RIGHT: + return kbRight; + case SL_KEY_PPAGE: + return kbPgUp; + case SL_KEY_NPAGE: + return kbPgDn; + case SL_KEY_HOME: + return kbHome; + case SL_KEY_END: + return kbEnd; + case SL_KEY_BACKSPACE: + case FTESL_KEY_BACKSP: + return kbBackSp; + case SL_KEY_ENTER: + case FTESL_KEY_ENTER: + return kbEnter; + case SL_KEY_IC: + return kbIns; + case SL_KEY_DELETE: + return kbDel; + case SL_KEY_F(1): + return kbF1; + case SL_KEY_F(2): + return kbF2; + case SL_KEY_F(3): + return kbF3; + case SL_KEY_F(4): + return kbF4; + case SL_KEY_F(5): + return kbF5; + case SL_KEY_F(6): + return kbF6; + case SL_KEY_F(7): + return kbF7; + case SL_KEY_F(8): + return kbF8; + case SL_KEY_F(9): + return kbF9; + case SL_KEY_F(10): + return kbF10; + case SL_KEY_F(11): + return kbF11; + case SL_KEY_F(12): + return kbF12; + case FTESL_KEY_TAB: + return kbTab; + case FTESL_KEY_ESC: + case SL_KEY_ERR: + return kbEsc; + default: + return '?'; + } +} + + +int ConGetEvent(TEventMask /*EventMask */ , + TEvent * Event, int WaitTime, int Delete) +{ + int key; + TKeyEvent *KEvent = &(Event->Key); + fd_set readfds; + struct timeval timeout; + + if (Prev.What != evNone) { + *Event = Prev; + if (Delete) + Prev.What = evNone; + return 1; + } + + Event->What = evNone; + + WaitTime = (WaitTime >= 0) ? WaitTime / 100 : 36000; + + FD_ZERO(&readfds); + + FD_SET(0, &readfds); + for (int p = 0; p < MAX_PIPES; p++) + if (Pipes[p].used && Pipes[p].fd != -1) + FD_SET(Pipes[p].fd, &readfds); + + if (WaitTime == -1) { + if (select(sizeof(fd_set) * 8, &readfds, NULL, NULL, NULL) < 0) + return -1; + } else { + timeout.tv_sec = WaitTime / 1000; + timeout.tv_usec = (WaitTime % 1000) * 1000; + if (select(sizeof(fd_set) * 8, &readfds, NULL, NULL, &timeout) < 0) + return -1; + } + + if (SLang_input_pending(0) > 0) { + TKeyCode kcode = 0, kcode1; + + key = SLang_getkey(); + int escfirst = 1; + + if (key == 27) + while (1) { + if (use_esc_hack) { + if (SLang_input_pending(1) == 0) { + kcode = kbEsc; + break; + } + } + + key = SLang_getkey(); + if (key == 3) { + SLang_ungetkey(key); + SLkp_getkey(); + } + if (key >= 'a' && key <= 'z') + key -= 'a' - 'A'; + if (key == 27) { + kcode = kbEsc; + break; + } else if (key == '[' && escfirst) { + unsigned char kbuf[2]; + + kbuf[0] = 27; + kbuf[1] = (char) key; + SLang_ungetkey_string(kbuf, 2); + key = SLkp_getkey(); + kcode = ftesl_process_key(key, 0); + break; + } else { + kcode1 = ftesl_process_key(key, 1); + if (keyCode(kcode1) == kbF1) { + key = SLang_getkey(); + switch (key) { + case '0': + kcode |= kbF10; + break; + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + kcode |= kbF1 + key - '1'; + break; + case 'a': + case 'b': + kcode |= kbF11 + key - 'a'; + break; + } + } else + kcode |= kcode1; + + if (keyCode(kcode) != 0) { + if (escfirst) + kcode |= kfAlt; + break; + } + } + escfirst = 0; + } else { + SLang_ungetkey(key); + key = SLkp_getkey(); + kcode = ftesl_process_key(key, 0); + } + + Event->What = evKeyDown; + KEvent->Code = kcode; + + if (!Delete) + Prev = *Event; + + return 1; + } else { + for (int pp = 0; pp < MAX_PIPES; pp++) { + if (Pipes[pp].used && Pipes[pp].fd != -1 && + FD_ISSET(Pipes[pp].fd, &readfds) && + Pipes[pp].notify) { + Event->What = evNotify; + Event->Msg.View = 0; + Event->Msg.Model = Pipes[pp].notify; + Event->Msg.Command = cmPipeRead; + Event->Msg.Param1 = pp; + Pipes[pp].stopped = 0; + } + //fprintf(stderr, "Pipe %d\n", Pipes[pp].fd); + return 0; + } + } + + return -1; +} + +int ConPutEvent(TEvent Event) +{ + Prev = Event; + return 0; +} + +GUI::GUI(int &argc, char **argv, int XSize, int YSize) +{ + fArgc = argc; + fArgv = argv; + ::ConInit(-1, -1); + ::ConSetSize(XSize, YSize); + gui = this; +} + +GUI::~GUI() +{ + ::ConDone(); + gui = 0; +} + +int GUI::ConSuspend(void) +{ + return::ConSuspend(); +} + +int GUI::ConContinue(void) +{ + return::ConContinue(); +} + +int GUI::ShowEntryScreen() +{ + TEvent E; + + ConHideMouse(); + do { + gui->ConGetEvent(evKeyDown, &E, -1, 1, 0); + } while (E.What != evKeyDown); + ConShowMouse(); + if (frames) + frames->Repaint(); + return 1; +} + +int GUI::OpenPipe(char *Command, EModel * notify) +{ + int i; + + for (i = 0; i < MAX_PIPES; i++) { + if (Pipes[i].used == 0) { + int pfd[2]; + + Pipes[i].id = i; + Pipes[i].notify = notify; + Pipes[i].stopped = 1; + + if (pipe((int *) pfd) == -1) + return -1; + + switch (Pipes[i].pid = fork()) { + case -1: /* fail */ + return -1; + case 0: /* child */ + signal(SIGPIPE, SIG_DFL); + close(pfd[0]); + close(0); + dup2(pfd[1], 1); + dup2(pfd[1], 2); + close(pfd[1]); + exit(system(Command)); + default: + close(pfd[1]); + fcntl(pfd[0], F_SETFL, O_NONBLOCK); + Pipes[i].fd = pfd[0]; + } + Pipes[i].used = 1; + return i; + } + } + return -1; +} + +int GUI::SetPipeView(int id, EModel * notify) +{ + if (id < 0 || id > MAX_PIPES) + return -1; + if (Pipes[id].used == 0) + return -1; + + Pipes[id].notify = notify; + return 0; +} + +int GUI::ReadPipe(int id, void *buffer, int len) +{ + int rc; + + if (id < 0 || id > MAX_PIPES) + return -1; + if (Pipes[id].used == 0) + return -1; + + rc = read(Pipes[id].fd, buffer, len); + if (rc == 0) { + close(Pipes[id].fd); + Pipes[id].fd = -1; + return -1; + } + if (rc == -1) { + Pipes[id].stopped = 1; + return 0; + } + return rc; +} + +int GUI::ClosePipe(int id) +{ + int status = -1; + + if (id < 0 || id > MAX_PIPES) + return -1; + if (Pipes[id].used == 0) + return -1; + if (Pipes[id].fd != -1) + close(Pipes[id].fd); + + kill(Pipes[id].pid, SIGHUP); + alarm(1); + waitpid(Pipes[id].pid, &status, 0); + alarm(0); + Pipes[id].used = 0; + return WEXITSTATUS(status); +} + +int GUI::RunProgram(int /*mode */ , char *Command) +{ + int rc, W, H, W1, H1; + + ConQuerySize(&W, &H); + ConHideMouse(); + ConSuspend(); + + if (*Command == 0) // empty string = shell + Command = getenv("SHELL"); + + rc = system(Command); + + ConContinue(); + ConShowMouse(); + ConQuerySize(&W1, &H1); + + if (W != W1 || H != H1) { + frames->Resize(W1, H1); + } + frames->Repaint(); + return rc; +} + +char ConGetDrawChar(int index) +{ + static const char * use_tab = NULL; + static int use_tab_size = 0; + + static const char tab[] = + { + DCH_SLANG_C1, + DCH_SLANG_C2, + DCH_SLANG_C3, + DCH_SLANG_C4, + DCH_SLANG_H, + DCH_SLANG_V, + DCH_SLANG_M1, + DCH_SLANG_M2, + DCH_SLANG_M3, + DCH_SLANG_M4, + DCH_SLANG_X, + DCH_SLANG_RPTR, + DCH_SLANG_EOL, + DCH_SLANG_EOF, + DCH_SLANG_END, + DCH_SLANG_AUP, + DCH_SLANG_ADOWN, + DCH_SLANG_HFORE, + DCH_SLANG_HBACK, + DCH_SLANG_ALEFT, + DCH_SLANG_ARIGHT + }; + + static const char tab_linux[] = + { + DCH_SLANG_C1, + DCH_SLANG_C2, + DCH_SLANG_C3, + DCH_SLANG_C4, + DCH_SLANG_H, + DCH_SLANG_V, + DCH_SLANG_M1, + DCH_SLANG_M2, + DCH_SLANG_M3, + DCH_SLANG_M4, + DCH_SLANG_X, + ' ', + '.', + DCH_SLANG_EOF, + DCH_SLANG_END, + DCH_SLANG_AUP, + DCH_SLANG_ADOWN, + DCH_SLANG_HFORE, + DCH_SLANG_HBACK, + DCH_SLANG_ALEFT, + DCH_SLANG_ARIGHT + }; + //static const char tab_linux1[] = + //{ + // '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + // 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'j', 'k', + // 'l', 'm', 'n', 'o', 'p', 'q' + //}; + + if (use_tab == NULL) { + char *c = getenv("TERM"); + use_tab = ((c == NULL) || strcmp(c, "linux") != 0) ? tab : tab_linux; + use_tab_size = (use_tab == tab) + ? sizeof(tab) : sizeof(tab_linux); + } + + assert(index >= 0 && index < use_tab_size); + + return use_tab[index]; +} diff --git a/src/con_x11.cpp b/src/con_x11.cpp new file mode 100644 index 0000000..39e4032 --- /dev/null +++ b/src/con_x11.cpp @@ -0,0 +1,1660 @@ +/* con_x11.cpp + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + * I18N & XMB support added by kabi@fi.muni.cz + */ + +#include +#include +#include +#ifdef WINNT +#include +#define NO_PIPES +#define NO_SIGNALS +#else +#include +#include +#include +#endif + +#include +#include +#include +#include +#include +#include +#if defined(AIX) +#include +#include +#endif +#include +#include +#include +#include +#include +#ifdef USE_XTINIT +#include +#endif +#ifdef HPUX +#include +#endif +#include "console.h" +#include "gui.h" + +#include "con_i18n.h" +#include "s_files.h" + +XIC xic = NULL; + +#ifdef WINHCLX +#include /* HCL - HCLXlibInit */ +#endif + +#ifdef CAST_FD_SET_INT +#define FD_SET_CAST() (int *) +#else +#define FD_SET_CAST() +#endif + +#define MIN_SCRWIDTH 20 +#define MIN_SCRHEIGHT 6 + +#define MAX_PIPES 40 +//#define PIPE_BUFLEN 4096 + +typedef struct { + int used; + int id; + int fd; + int pid; + int stopped; + EModel *notify; +} GPipe; + +static GPipe Pipes[MAX_PIPES] = { + { 0 }, +}; + +static long MouseAutoDelay = 40; +static long MouseAutoRepeat = 200; +static long MouseMultiClick = 300; + +static int setUserPosition = 0; +static int initX = 0, initY = 0; +static unsigned int ScreenCols = 80; +static unsigned int ScreenRows = 40; +static unsigned int CursorX = 0; +static unsigned int CursorY = 0; +static int CursorVisible = 1; +static unsigned char *ScreenBuffer = NULL; +static int Refresh = 0; + +static Display *display; +static Colormap colormap; +static Atom wm_protocols; +static Atom wm_delete_window; +static Atom targets; +static Window win; +static Atom selection_buffer; +static XSizeHints sizeHints; +// program now contains both modes if available +// some older Xservers don't like XmbDraw... +static XFontStruct *fontStruct; +#ifdef USE_XMB +static int useXMB = 1; // default is yes +static XFontSet fontSet; +static int FontCYD; +#else +static int useXMB = 0; +#endif +static int FontCX, FontCY; +static XColor Colors[16]; +static GC GCs[256]; +static int rc; +static char winTitle[256] = "FTE"; +static char winSTitle[256] = "FTE"; + +static char *CurSelectionData = 0; +static int CurSelectionLen = 0; +static int CurSelectionOwn = 0; +static Time now; + +static int AllocBuffer() { + unsigned char *p; + unsigned int i; + + ScreenBuffer = (unsigned char *)malloc(2 * ScreenCols * ScreenRows); + if (ScreenBuffer == NULL) return -1; + for (i = 0, p = ScreenBuffer; i < ScreenCols * ScreenRows; i++) { + *p++ = 32; + *p++ = 0x07; + } + return 0; +} + +static struct { + int r, g, b; +} dcolors[] = +{ + { 0, 0, 0 }, // black + { 0, 0, 160 }, // darkBlue + { 0, 160, 0 }, // darkGreen + { 0, 160, 160 }, // darkCyan + { 160, 0, 0 }, // darkRed + { 160, 0, 160 }, // darkMagenta + { 160, 160, 0 }, // darkYellow + { 204, 204, 204 }, // paleGray + { 160, 160, 160 }, // darkGray + { 0, 0, 255 }, // blue + { 0, 255, 0 }, // green + { 0, 255, 255 }, // cyan + { 255, 0, 0 }, // red + { 255, 0, 255 }, // magenta + { 255, 255, 0 }, // yellow + { 255, 255, 255 }, // white +}; + +static void SetColor(int i) { + assert (0 <= i && i <= 15); + Colors[i].blue = (dcolors[i].b << 8) | dcolors[i].b; + Colors[i].green = (dcolors[i].g << 8) | dcolors[i].g; + Colors[i].red = (dcolors[i].r << 8) | dcolors[i].r; + Colors[i].flags = DoRed | DoGreen | DoBlue; +} + +static int InitXColors() { + int i, j; + long d = 0x7FFFFFFF, d1; + XColor clr; + unsigned long pix; + int num; + long d_red, d_green, d_blue; + long u_red, u_green, u_blue; + + for (i = 0; i < 16; i++) { + SetColor(i); + if (XAllocColor(display, colormap, &Colors[i]) == 0) { + SetColor(i); + pix = 0xFFFFFFFF; + num = DisplayCells(display, DefaultScreen(display)); + for (j = 0; j < num; j++) { + clr.pixel = j; + XQueryColor(display, colormap, &clr); + + d_red = (clr.red - Colors[i].red) >> 3; + d_green = (clr.green - Colors[i].green) >> 3; + d_blue = (clr.blue - Colors[i].blue) >> 3; + + //fprintf(stderr, "%d:%d dr:%d, dg:%d, db:%d\n", i, j, d_red, d_green, d_blue); + + u_red = d_red / 100 * d_red * 3; + u_green = d_green / 100 * d_green * 4; + u_blue = d_blue / 100 * d_blue * 2; + + //fprintf(stderr, "%d:%d dr:%u, dg:%u, db:%u\n", i, j, u_red, u_green, u_blue); + + d1 = u_red + u_blue + u_green; + + if (d1 < 0) + d1 = -d1; + if (pix == ~0UL || d1 < d) { + pix = j; + d = d1; + } + } + if (pix == 0xFFFFFFFF) { + fprintf(stderr, "Color search failed for #%04X%04X%04X\n", + Colors[i].red, + Colors[i].green, + Colors[i].blue); + } + clr.pixel = pix; + XQueryColor(display, colormap, &clr); + Colors[i] = clr; + if (XAllocColor(display, colormap, &Colors[i]) == 0) { + fprintf(stderr, "Color alloc failed for #%04X%04X%04X\n", + Colors[i].red, + Colors[i].green, + Colors[i].blue); + } + /*colormap = XCreateColormap(display, win, DefaultVisual(display, screen), AllocNone); + for (i = 0; i < 16; i++) { + SetColor(i); + XAllocColor(display, colormap, &Colors[i]); + } + XSetWindowColormap(display, win, colormap); + return 0;*/ + } + } + return 0; +} + +static int InitXGCs() { + unsigned int i; + unsigned long mask = GCForeground | GCBackground; + XGCValues gcv; + + if (!useXMB) { + gcv.font = fontStruct->fid; + mask |= GCFont; + } + + for (i = 0; i < 256; i++) { + gcv.foreground = Colors[i % 16].pixel; + gcv.background = Colors[(i / 16)].pixel; + GCs[i] = XCreateGC(display, win, mask, &gcv); + } + + return 0; +} + +static int InitXFonts(void) +{ + char *fs; + + fs = getenv("VIOFONT"); + if (fs == NULL && WindowFont[0] != 0) + fs = WindowFont; + + if (!useXMB) { + + fontStruct = NULL; + + if (fs != NULL) { + char *s = 0; + + s = strchr(fs, ','); + if (s != NULL) + *s = 0; + fontStruct = XLoadQueryFont(display, fs); + } + if (fontStruct == NULL) + fontStruct = XLoadQueryFont(display, "8x13"); + if (fontStruct == NULL) + fontStruct = XLoadQueryFont(display, "fixed"); + if (fontStruct == NULL) + return -1; + FontCX = fontStruct->max_bounds.width; + FontCY = fontStruct->max_bounds.ascent + fontStruct->max_bounds.descent; + } +#ifdef USE_XMB + else { + const char *def = " "; + const char *fs1 = "-misc-*-r-normal-*"; + const char *fs2 = "*fixed*"; + char **miss; + int nMiss; + + // test font fixed font: + // fs="*-fixed-bold-*-15-*"; + if (fs != NULL) + fontSet = XCreateFontSet(display, fs, &miss, &nMiss, + (char **) &def); + + // try any fixed localized font */ + if (fontSet == NULL) { + fprintf(stderr, "XFTE Warning: unable to open font: '%s'\n" + " using '%s' instead\n", fs, fs1); + fontSet = XCreateFontSet(display, fs1, &miss, &nMiss, + (char **) &def); + } + + // try plain fixed font + if (fontSet == NULL) { + fprintf(stderr, "XFTE Warning: unable to open font: '%s'\n" + " using '%s' instead\n", fs1, fs2); + fontSet = XCreateFontSet(display, fs2, &miss, &nMiss, + (char **) &def); + } + + if (fontSet == NULL) { + fprintf(stderr, "XFTE Warning: unable to open \"base\" font: " + "'%s'\n Missing count: %d\n", fs2, nMiss); + for(int i = 0; i < nMiss; i++) + fprintf(stderr, " %s\n", miss[i]); + if (def != NULL) + fprintf(stderr, " def_ret: %s\n", def); + } + + if (fontSet == NULL) + return -1; + XFontSetExtents *xE = XExtentsOfFontSet(fontSet); + + FontCX = xE->max_logical_extent.width; + FontCY = xE->max_logical_extent.height; + // handle descending (comes in negative form) + FontCYD = -(xE->max_logical_extent.y); + // printf("Font X:%d\tY:%d\tD:%d\n", FontCX, FontCY, FontCYD); + } +#endif + return 0; +} + +static int SetupXWindow(int argc, char **argv) { + unsigned long mask; + XSetWindowAttributes setWindowAttributes; + +#ifdef WINHCLX + HCLXlibInit(); /* HCL - Initialize the X DLL */ +#endif + +#ifdef USE_XTINIT + XtAppContext app_context; + XtToolkitInitialize(); + app_context = XtCreateApplicationContext(); + if (( display = XtOpenDisplay(app_context, NULL, argv[0], "xfte", + NULL, 0, &argc, argv)) == NULL) + DieError(1, "%s: Can't open display\n", argv[0]); +#else + char *ds; + if ((ds = getenv("DISPLAY")) == NULL) + DieError(1, "$DISPLAY not set?"); + if ((display = XOpenDisplay(ds)) == NULL) + DieError(1, "XFTE Fatal: could not open display: %s!", ds); +#endif + + colormap = DefaultColormap(display, DefaultScreen(display)); + + setWindowAttributes.bit_gravity = + sizeHints.win_gravity = NorthWestGravity; + + // this is correct behavior + if (initX < 0) + initX = DisplayWidth(display, DefaultScreen(display)) + initX; + if (initY < 0) + initY = DisplayHeight(display, DefaultScreen(display)) + initY; + win = XCreateWindow(display, + DefaultRootWindow(display), + initX, initY, + // ScreenCols * FontCX, ScreenRows * FontCY, 0, + // at this moment we don't know the exact size + // but we need to open a window - so pick up 1 x 1 + 1, 1, 0, + CopyFromParent, InputOutput, CopyFromParent, + CWBitGravity, &setWindowAttributes); + + xic = I18NInit(display, win, &mask); + + if (InitXFonts() != 0) + DieError(1, "XFTE Fatal: could not open any font!"); + + /* >KeyReleaseMask shouldn't be set for correct key mapping */ + /* we set it anyway, but not pass to XmbLookupString -- mark */ + mask |= ExposureMask | StructureNotifyMask | VisibilityChangeMask | + FocusChangeMask | KeyPressMask | KeyReleaseMask | + ButtonPressMask | ButtonReleaseMask | ButtonMotionMask; + XSelectInput(display, win, mask); + + wm_protocols = XInternAtom(display, "WM_PROTOCOLS", False); + assert(wm_protocols != None); + wm_delete_window = XInternAtom(display, "WM_DELETE_WINDOW", False); + assert(wm_delete_window != None); + selection_buffer = XInternAtom(display, "fte_clip", False);//??? needed + assert(selection_buffer != None); + targets = XInternAtom(display, "TARGETS", False); + assert(targets != None); + + sizeHints.flags = PResizeInc | PMinSize | PBaseSize | PWinGravity; + sizeHints.width_inc = FontCX; + sizeHints.height_inc = FontCY; + sizeHints.min_width = MIN_SCRWIDTH * FontCX; + sizeHints.min_height = MIN_SCRHEIGHT * FontCY; + sizeHints.base_width = 0; + sizeHints.base_height = 0; + if (setUserPosition) + sizeHints.flags |= USPosition; + + XClassHint classHints; + classHints.res_name = (char *)"fte"; + classHints.res_class = (char *)"Fte"; + XSetClassHint(display, win, &classHints); + + XSetStandardProperties(display, win, winTitle, winTitle, 0, NULL, 0, 0); + XSetWMNormalHints(display, win, &sizeHints); + XSetWMProtocols(display, win, &wm_delete_window, 1); + + if (InitXColors() != 0) return -1; + if (InitXGCs() != 0) return -1; + + XResizeWindow(display, win, ScreenCols * FontCX, ScreenRows * FontCY); + XMapRaised(display, win); + // XClearWindow(display, win); /// !!! why? + return 0; +} + +int ConInit(int XSize, int YSize) { + if (XSize != -1) + ScreenCols = XSize; + if (YSize != -1) + ScreenRows = YSize; + if (AllocBuffer() == -1) return -1; +#ifndef NO_SIGNALS + signal(SIGALRM, SIG_IGN); + signal(SIGPIPE, SIG_IGN); +#endif + return 0; +} + +int ConDone(void) { + XDestroyWindow(display, win); + XCloseDisplay(display); + return 0; +} + +int ConSuspend(void) { + return 0; +} + +int ConContinue(void) { + return 0; +} + +int ConClear(void) { + TDrawBuffer B; + MoveCh(B, ' ', 0x07, ScreenCols); + return ConPutLine(0, 0, ScreenCols, ScreenRows, B); +} + +int ConSetTitle(char *Title, char *STitle) { + char buf[sizeof(winTitle)] = {0}; + JustFileName(Title, buf); + if (buf[0] == '\0') // if there is no filename, try the directory name. + JustLastDirectory(Title, buf); + + strncpy(winTitle, "FTE - ", sizeof(winTitle) - 1); + if (buf[0] != 0) // if there is a file/dir name, stick it in here. + { + strncat(winTitle, buf, sizeof(winTitle) - 1 - strlen(winTitle)); + strncat(winTitle, " - ", sizeof(winTitle) - 1 - strlen(winTitle)); + } + strncat(winTitle, Title, sizeof(winTitle) - 1 - strlen(winTitle)); + winTitle[sizeof(winTitle) - 1] = 0; + strncpy(winSTitle, STitle, sizeof(winSTitle) - 1); + winSTitle[sizeof(winSTitle) - 1] = 0; + XSetStandardProperties(display, win, winTitle, winSTitle, 0, NULL, 0, NULL); + return 0; +} + +int ConGetTitle(char *Title, int MaxLen, char *STitle, int SMaxLen) { + strncpy(Title, winTitle, MaxLen); + Title[MaxLen - 1] = 0; + strncpy(STitle, winSTitle, SMaxLen); + STitle[SMaxLen - 1] = 0; + return 0; +} + +#define InRange(x,a,y) (((x) <= (a)) && ((a) < (y))) +#define CursorXYPos(x,y) (ScreenBuffer + ((x) + ((y) * ScreenCols)) * 2) + +void DrawCursor(int Show) { + if (CursorVisible) { + unsigned char *p = CursorXYPos(CursorX, CursorY), attr; + attr = p[1]; + /*if (Show) attr = ((((attr << 4) & 0xF0)) | (attr >> 4)) ^ 0x77;*/ + if (Show) + attr = (attr ^ 0x77); + + if (!useXMB) + XDrawImageString(display, win, GCs[((unsigned)attr) & 0xFF], + CursorX * FontCX, + fontStruct->max_bounds.ascent + CursorY * FontCY, + (char *)p, 1); +#ifdef USE_XMB + else + XmbDrawImageString(display, win, fontSet, + GCs[((unsigned)attr) & 0xFF], + CursorX * FontCX, FontCYD + CursorY * FontCY, + (char *)p, 1); +#endif + } +} + +int ConPutBox(int X, int Y, int W, int H, PCell Cell) { + unsigned int i; + unsigned char temp[256], attr; + unsigned char *p, *ps, *c, *ops; + unsigned int len, x, l, ox, olen, skip; + + + if (X >= (int) ScreenCols || Y >= (int) ScreenRows || + X + W > (int) ScreenCols || Y + H > (int) ScreenRows) { + //fprintf(stderr, "%d %d %d %d %d %d\n", ScreenCols, ScreenRows, X, Y, W, H); + return -1; + } + //XClearArea(display, win, X, Y, W * FontCX, H * FontCY, False); + + //fprintf(stderr, "%d %d %d %d %d %d\n", ScreenCols, ScreenRows, X, Y, W, H); + for (i = 0; i < (unsigned int)H; i++) { + len = W; + p = CursorXYPos(X, Y + i); + ps = (unsigned char *) Cell; + x = X; + while (len > 0) { + if (!Refresh) { + c = CursorXYPos(x, Y + i); + skip = 0; + ops = ps; + ox = x; + olen = len; + while ((len > 0) && c[0] == ps[0] && c[1] == ps[1] ) + { + ps+=2; + c+=2; + x++; + len--; + skip++; + } + if (len <= 0) break; + if (skip <= 4) { + ps = ops; + x = ox; + len = olen; + } + } + p = ps; + l = 1; + temp[0] = *ps++; attr = *ps++; + while ((l < len) && ((unsigned char) (ps[1]) == attr)) { + temp[l++] = *ps++; + ps++; + } + if (!useXMB) + XDrawImageString(display, win, GCs[((unsigned)attr) & 0xFF], + x * FontCX, fontStruct->max_bounds.ascent + + (Y + i) * FontCY, + (char *)temp, l); +#ifdef USE_XMB + else + XmbDrawImageString(display, win, fontSet, + GCs[((unsigned)attr) & 0xFF], + x * FontCX, FontCYD + (Y + i) * FontCY, + (char *)temp, l); +#endif + //temp[l] = 0; printf("%s\n", temp); + len -= l; + x += l; + } +/* if (x < ScreenCols - 1) { + printf("XX %d %d %d\n", X, x, W); + XFillRectangle(display, win, GCs[15 * 16 + 7], + x * FontCX, (Y + i) * FontCY, + (ScreenCols - x - 1) * FontCX, FontCY); + } +*/ p = CursorXYPos(X, Y + i); + memcpy(p, Cell, W * 2); + if (i + Y == CursorY) + DrawCursor(1); + Cell += W; + } + return 0; +} + +int ConGetBox(int X, int Y, int W, int H, PCell Cell) { + int i; + + for (i = 0; i < H; i++) { + memcpy(Cell, CursorXYPos(X, Y + i), 2 * W); + Cell += W; + } + return 0; +} + +int ConPutLine(int X, int Y, int W, int H, PCell Cell) { + int i; + for (i = 0; i < H; i++) { + if (ConPutBox(X, Y + i, W, 1, Cell) != 0) return -1; + } + return 0; +} + +int ConSetBox(int X, int Y, int W, int H, TCell Cell) { + TDrawBuffer B; + int i; + + for (i = 0; i < W; i++) + B[i] = Cell; + ConPutLine(X, Y, W, H, B); + return 0; +} + +int ConScroll(int Way, int X, int Y, int W, int H, TAttr Fill, int Count) { + TCell Cell; + int l; + + MoveCh(&Cell, ' ', Fill, 1); + DrawCursor(0); + if (Way == csUp) { + XCopyArea(display, win, win, GCs[0], + X * FontCX, + (Y + Count) * FontCY, + W * FontCX, + (H - Count) * FontCY, + X * FontCX, + Y * FontCY); + for (l = 0; l < H - Count; l++) + memcpy(CursorXYPos(X, Y + l), CursorXYPos(X, Y + l + Count), 2 * W); + + if (ConSetBox(X, Y + l, W, Count, Cell) == -1) + return -1; + } else if (Way == csDown) { + XCopyArea(display, win, win, GCs[0], + X * FontCX, + Y * FontCY, + W * FontCX, + (H - Count) * FontCY, + X * FontCX, + (Y + Count) * FontCY); + for (l = H - 1; l >= Count; l--) + memcpy(CursorXYPos(X, Y + l), CursorXYPos(X, Y + l - Count), 2 * W); + + if (ConSetBox(X, Y, W, Count, Cell) == -1) + return -1; + } + DrawCursor(1); + return 0; +} + +int ConSetSize(int X, int Y) { + unsigned char *NewBuffer; + unsigned char *p; + int i; + int MX, MY; + + p = NewBuffer = (unsigned char *) malloc(X * Y * 2); + if (NewBuffer == NULL) return -1; + for (i = 0; i < X * Y; i++) { + *p++ = ' '; + *p++ = 0x07; + } + MX = ScreenCols; + if (X < MX) + MX = X; + MY = ScreenRows; + if (Y < MY) + MY = Y; + p = NewBuffer; + for (i = 0; i < MY; i++) { + memcpy(p, CursorXYPos(0, i), MX * 2); + p += X * 2; + } + free(ScreenBuffer); + ScreenBuffer = NewBuffer; + ScreenCols = X; + ScreenRows = Y; + //ConPutBox(0, 0, ScreenCols, ScreenRows, (PCell) ScreenBuffer); + //if (Refresh == 0) + // XResizeWindow(display, win, ScreenCols * FontCX, ScreenRows * FontCY); + return 0; +} + +int ConQuerySize(int *X, int *Y) { + *X = ScreenCols; + *Y = ScreenRows; + return 0; +} + +int ConSetCursorPos(int X, int Y) { + DrawCursor(0); + CursorX = X; + CursorY = Y; + DrawCursor(1); + return 0; +} + +int ConQueryCursorPos(int *X, int *Y) { + *X = CursorX; + *Y = CursorY; + return 0; +} + +int ConShowCursor(void) { + CursorVisible = 1; + DrawCursor(1); + return 0; +} + +int ConHideCursor(void) { + DrawCursor(0); + CursorVisible = 0; + return 0; +} + +int ConCursorVisible(void) { + return 1; +} +int ConSetCursorSize(int Start, int End) { + return 1; +} + +int ConSetMousePos(int X, int Y) { + return 0; +} + +static int LastMouseX = -1, LastMouseY = -1; + +int ConQueryMousePos(int *X, int *Y) { + if (X) *X = LastMouseX; + if (Y) *Y = LastMouseY; + return 0; +} + +int ConShowMouse(void) { + printf("Show\n"); + return 0; +} + +int ConHideMouse(void) { + printf("Hide\n"); + return 0; +} + +int ConMouseVisible(void) { + return 1; +} + +int ConQueryMouseButtons(int *ButtonCount) { + *ButtonCount = 3; + return 0; +} + +void UpdateWindow(int xx, int yy, int ww, int hh) { + PCell p; + int i; + + /* show redrawn area */ + /* + XFillRectangle(display, win, GCs[14], xx, yy, ww, hh); + XFlush(display); + i = XEventsQueued(display, QueuedAfterReading); + while (i-- > 0) { + XEvent e; + XNextEvent(display, &e); + } + // sleep(1);*/ + + ww /= FontCX; ww += 2; + hh /= FontCY; + xx /= FontCX; + yy /= FontCY; + + /* + * OK for this moment I suggest this method - it works somehow + * But I suppose the correct solution would meant general rewrite + * of some basic behavior of FTE editor + * THIS IS TEMPORAL FIX AND SHOULD BE SOLVED IN GENERAL WAY ! + */ + hh *= 3; yy -= hh; hh += hh + 2; + if (yy < 0) + yy = 0; + if (xx + ww > (int)ScreenCols) ww = ScreenCols - xx; + if (yy + hh > (int)ScreenRows) hh = ScreenRows - yy; + Refresh = 1; + //frames->Repaint(); + //frames->Update(); + p = (PCell) CursorXYPos(xx, yy); + for (i = 0; i < hh; i++) { + ConPutBox(xx, yy + i, ww, 1, p); + p += ScreenCols; + } + //fprintf(stderr, "UPDATE\tx:%3d y:%3d w:%3d h:%3d\n", xx, yy, ww, hh); + //XFlush(display); + Refresh = 0; +} + +void ResizeWindow(int ww, int hh) { + int ox = ScreenCols; + int oy = ScreenRows; + ww /= FontCX; if (ww <= 4) ww = 4; + hh /= FontCY; if (hh <= 2) hh = 2; + if ((int)ScreenCols != ww || (int)ScreenRows != hh) { + Refresh = 0; + ConSetSize(ww, hh); + Refresh = 1; + if (ox < (int)ScreenCols) + UpdateWindow(ox * FontCX, 0, + (ScreenCols - ox) * FontCX, ScreenRows * FontCY); + if (oy < (int)ScreenRows) + UpdateWindow(0, oy * FontCY, + ScreenCols * FontCX, (ScreenRows - oy) * FontCY); + Refresh = 0; + } +} + +static struct { + long keysym; + long keycode; +} key_table[] = { + { XK_Escape, kbEsc }, + { XK_Tab, kbTab }, + { XK_Return, kbEnter }, + { XK_Pause, kbPause }, + { XK_BackSpace, kbBackSp }, + { XK_Home, kbHome }, + { XK_Up, kbUp }, + { XK_Prior, kbPgUp }, + { XK_Left, kbLeft }, + { XK_Right, kbRight }, + { XK_End, kbEnd }, + { XK_Down, kbDown }, + { XK_Next, kbPgDn }, + { XK_Select, kbEnd }, + { XK_KP_Enter, kbEnter | kfGray }, + { XK_Insert, kbIns | kfGray }, + { XK_Delete, kbDel | kfGray }, + { XK_KP_Add, '+' | kfGray }, + { XK_KP_Subtract, '-' | kfGray }, + { XK_KP_Multiply, '*' | kfGray }, + { XK_KP_Divide, '/' | kfGray }, + { XK_KP_Begin, kbPgUp | kfGray | kfCtrl }, + { XK_KP_Home, kbHome | kfGray }, + { XK_KP_Up, kbUp | kfGray }, + { XK_KP_Prior, kbPgUp | kfGray }, + { XK_KP_Left, kbLeft | kfGray }, + { XK_KP_Right, kbRight | kfGray }, + { XK_KP_End, kbEnd | kfGray }, + { XK_KP_Down, kbDown | kfGray }, + { XK_KP_Next, kbPgDn| kfGray }, + { XK_Num_Lock, kbNumLock }, + { XK_Caps_Lock, kbCapsLock }, + { XK_Print, kbPrtScr }, + { XK_Shift_L, kbShift }, + { XK_Shift_R, kbShift | kfGray }, + { XK_Control_L, kbCtrl }, + { XK_Control_R, kbCtrl | kfGray }, + { XK_Alt_L, kbAlt }, + { XK_Alt_R, kbAlt | kfGray }, + { XK_Meta_L, kbAlt }, + { XK_Meta_R, kbAlt | kfGray }, + { XK_F1, kbF1 }, + { XK_F2, kbF2 }, + { XK_F3, kbF3 }, + { XK_F4, kbF4 }, + { XK_F5, kbF5 }, + { XK_F6, kbF6 }, + { XK_F7, kbF7 }, + { XK_F8, kbF8 }, + { XK_F9, kbF9 }, + { XK_F10, kbF10 }, + { XK_F11, kbF11 }, + { XK_F12, kbF12 }, + { XK_KP_0, '0' | kfGray }, + { XK_KP_1, '1' | kfGray }, + { XK_KP_2, '2' | kfGray }, + { XK_KP_3, '3' | kfGray }, + { XK_KP_4, '4' | kfGray }, + { XK_KP_5, '5' | kfGray }, + { XK_KP_6, '6' | kfGray }, + { XK_KP_7, '7' | kfGray }, + { XK_KP_8, '8' | kfGray }, + { XK_KP_9, '9' | kfGray }, + { XK_KP_Decimal, '.' | kfGray }, + { 0x1000FF6F, kbDel | kfShift | kfGray }, + { 0x1000FF70, kbIns | kfCtrl | kfGray }, + { 0x1000FF71, kbIns | kfShift | kfGray }, + { 0x1000FF72, kbIns | kfGray }, + { 0x1000FF73, kbDel | kfGray }, + { 0x1000FF74, kbTab | kfShift }, + { 0x1000FF75, kbTab | kfShift }, + { 0, 0 } +}; + +void ConvertKeyToEvent(KeySym key, KeySym key1, char *keyname, char *keyname1, int etype, int state, TEvent *Event) { + unsigned int myState = 0; + + Event->What = evNone; + + switch (etype) { + case KeyPress: Event->What = evKeyDown; break; + case KeyRelease: Event->What = evKeyUp; break; + default: + return ; + } + + if (state & ShiftMask) myState |= kfShift; + if (state & ControlMask) myState |= kfCtrl; + if (state & Mod1Mask) myState |= kfAlt; + + /* modified kabi@fi.muni.cz + * for old method + * if (!KeyAnalyze((etype == KeyPress), state, &key, &key1)) + * return; + */ + + //printf("key: %d ; %d ; %d\n", key, key1, state); + if (key < 256 || (key1 < 256 && (myState == kfAlt || myState == (kfAlt | kfShift)))) { + if (myState & kfAlt) + key = key1; + if (myState == kfShift) + myState = 0; + if (myState & (kfAlt | kfCtrl)) + if ((key >= 'a') && (key < 'z' + 32)) + key &= ~0x20; + if ((myState & kfCtrl) && key < 32) + key += 64; + Event->Key.Code = key | myState; + return; + } else { + for (unsigned i = 0; i < (sizeof(key_table) / sizeof(key_table[0])); i++) { + long k; + + if ((long) key1 == key_table[i].keysym) { + k = key_table[i].keycode; + if (k < 256) + if (myState == kfShift) + myState = 0; + Event->Key.Code = k | myState; + return; + } + } + } + //printf("Unknown key: %ld %s %d %d\n", key, keyname, etype, state); + Event->What = evNone; +} + + +static TEvent LastMouseEvent = { evNone }; + +#define TM_DIFF(x,y) ((long)(((long)(x) < (long)(y)) ? ((long)(y) - (long)(x)) : ((long)(x) - (long)(y)))) + +void ConvertClickToEvent(int type, int xx, int yy, int button, int state, TEvent *Event, Time time) { + unsigned int myState = 0; + static unsigned long LastClickTime = 0; + static short LastClickCount = 0; + static unsigned long LastClick = 0; + unsigned long CurTime = time; + + if (type == MotionNotify) Event->What = evMouseMove; + else if (type == ButtonPress) Event->What = evMouseDown; + else Event->What = evMouseUp; + Event->Mouse.X = xx / FontCX; + Event->Mouse.Y = yy / FontCY; + if (Event->What == evMouseMove) + if (LastMouseX == Event->Mouse.X + && LastMouseY == Event->Mouse.Y) { + Event->What = evNone; + return; + } + LastMouseX = Event->Mouse.X; + LastMouseY = Event->Mouse.Y; + Event->Mouse.Buttons = 0; + if (type == MotionNotify) { + if (state & Button1Mask) Event->Mouse.Buttons |= 1; + if (state & Button2Mask) Event->Mouse.Buttons |= 4; + if (state & Button3Mask) Event->Mouse.Buttons |= 2; + } else { + switch (button) { + case Button1: Event->Mouse.Buttons |= 1; break; + case Button2: Event->Mouse.Buttons |= 4; break; + case Button3: Event->Mouse.Buttons |= 2; break; + case Button4: + case Button5: + if (type == ButtonPress) { + Event->What = evCommand; + if (state & ShiftMask) { + if (button == Button4) + Event->Msg.Command = cmHScrollPgLt; // fix core to use count + else + Event->Msg.Command = cmHScrollPgRt; + } else { + if (button == Button4) + Event->Msg.Command = cmVScrollPgUp; + else + Event->Msg.Command = cmVScrollPgDn; + } + } + return ; + } + } + Event->Mouse.Count = 1; + if (state & ShiftMask) myState |= kfShift; + if (state & ControlMask) myState |= kfCtrl; + if (state & Mod1Mask) myState |= kfAlt; +// if (state & Mod2Mask) myState |= kfAlt; +// if (state & Mod3Mask) myState |= kfAlt; +// if (state & Mod4Mask) myState |= kfAlt; + Event->Mouse.KeyMask = myState; + + if (Event->What == evMouseDown) { + if (LastClickCount) { + if (LastClick == Event->Mouse.Buttons) { + if (TM_DIFF(CurTime, LastClickTime) <= MouseMultiClick) { + Event->Mouse.Count = ++LastClickCount; + } else { + LastClickCount = 0; + } + } else { + LastClick = 0; + LastClickCount = 0; + LastClickTime = 0; + } + } + + LastClick = Event->Mouse.Buttons; + if (LastClickCount == 0) + LastClickCount = 1; + LastClickTime = CurTime; + } + /* if (Event->What == evMouseMove) { + LastClick = 0; + LastClickCount = 0; + LastClickTime = 0; + } + */ + LastMouseEvent = *Event; +} + +void ProcessXEvents(TEvent *Event) { + XEvent event; + XAnyEvent *anyEvent = (XAnyEvent *) &event; + XExposeEvent *exposeEvent = (XExposeEvent *) &event; + XButtonEvent *buttonEvent = (XButtonEvent *) &event; + XKeyEvent *keyEvent = (XKeyEvent *) &event; + XKeyEvent keyEvent1; + XConfigureEvent *configureEvent = (XConfigureEvent *) &event; + XGraphicsExposeEvent *gexposeEvent = (XGraphicsExposeEvent *) &event; + XMotionEvent *motionEvent = (XMotionEvent *) &event; + KeySym key, key1; + int state; + char keyName[32]; + char keyName1[32]; + + memset((void *)&event, 0, sizeof(event)); + Event->What = evNone; +#ifdef WINNT + rc = -1; +#else + rc = +#endif + XNextEvent(display, &event); + + if (XFilterEvent(&event, None)) + return; + + if (event.type == MappingNotify) { + XRefreshKeyboardMapping(&event.xmapping); + return; + } + + if (anyEvent->window != win) + return; + + switch (event.type) { + case Expose: + //fprintf(stderr, "EXPOSE\tx:%3d y:%3d w:%3d h:%3d\n", + // exposeEvent->x, exposeEvent->y, + // exposeEvent->width, exposeEvent->height); + UpdateWindow(exposeEvent->x, + exposeEvent->y, + exposeEvent->width, + exposeEvent->height); + break; + case GraphicsExpose: + /* catch up same events to speed up this a bit */ + state = XEventsQueued(display, QueuedAfterReading); + // printf("Event %d\n", state); + while (state-- > 0) { + XEvent e; + XGraphicsExposeEvent *ge = (XGraphicsExposeEvent *) &e; + + if (XCheckTypedWindowEvent(display, win, GraphicsExpose, &e)) { + if (gexposeEvent->x == ge->x + && gexposeEvent->y == ge->y + && gexposeEvent->width == ge->width + && gexposeEvent->height == ge->height) { + // fprintf(stderr, "found the same gexpose event\n"); + continue; + } else { + // fprintf(stderr, "caught different gexpose event\n"); + XPutBackEvent(display, &e); + } + } + break; + } + //fprintf(stderr, "GEXPOSE\tx:%3d y:%3d w:%3d h:%3d\n", + // gexposeEvent->x, gexposeEvent->y, + // gexposeEvent->width, gexposeEvent->height); + UpdateWindow(gexposeEvent->x, + gexposeEvent->y, + gexposeEvent->width, + gexposeEvent->height); + break; + case ConfigureNotify: + while ((XPending(display) > 0) && + XCheckTypedWindowEvent(display, win, + ConfigureNotify, &event)) + XSync(display, 0); + ResizeWindow(configureEvent->width, configureEvent->height); + Event->What = evCommand; + Event->Msg.Command = cmResize; + break; + case ButtonPress: + case ButtonRelease: + now = event.xbutton.time; + ConvertClickToEvent(event.type, buttonEvent->x, buttonEvent->y, buttonEvent->button, buttonEvent->state, Event, motionEvent->time); + break; + case FocusIn: + I18NFocusIn(xic); + break; + case FocusOut: + I18NFocusOut(xic); + break; + case KeyPress: + // case KeyRelease: + now = event.xkey.time; + state = keyEvent->state; + keyEvent1 = *keyEvent; + keyEvent1.state &= ~(ShiftMask | ControlMask | Mod1Mask | Mod2Mask | Mod3Mask | Mod4Mask); + + if (event.type == KeyRelease) + XLookupString(keyEvent, keyName, sizeof(keyName), &key, 0); + else { + I18NLookupString(keyEvent, keyName, sizeof(keyName), &key, xic); + if (!key) + break; + } + XLookupString(&keyEvent1, keyName1, sizeof(keyName1), &key1, 0); + //printf("keyEvent->state = %d %s %08X\n", keyEvent->state, keyName, key); + //printf("keyEvent1.state = %d %s %08X\n", keyEvent1.state, keyName1, key1); + //key1 = XLookupKeysym(keyEvent, 0); + ConvertKeyToEvent(key, key1, keyName, keyName1, event.type, state, Event); + break; + case MotionNotify: + now = event.xmotion.time; + ConvertClickToEvent(event.type, motionEvent->x, motionEvent->y, 0, motionEvent->state, Event, motionEvent->time); + break; + case ClientMessage: + if (event.xclient.message_type == wm_protocols + && event.xclient.format == 32 + && (Atom)event.xclient.data.l[0] == wm_delete_window) + { + Event->What = evCommand; + Event->Msg.Command = cmClose; + } + break; + case SelectionClear: + { + Window owner; + + owner = XGetSelectionOwner(display, XA_PRIMARY); + if (owner != win) { + if (CurSelectionData != 0) + free(CurSelectionData); + CurSelectionData = 0; + CurSelectionLen = 0; + CurSelectionOwn = 0; + } + } + break; + case SelectionRequest: + { + XEvent notify; + + notify.type = SelectionNotify; + notify.xselection.requestor = event.xselectionrequest.requestor; + notify.xselection.selection = event.xselectionrequest.selection; + notify.xselection.target = event.xselectionrequest.target; + notify.xselection.time = event.xselectionrequest.time; + + if (event.xselectionrequest.selection == XA_PRIMARY && + event.xselectionrequest.target == XA_STRING) + { + XChangeProperty(display, + event.xselectionrequest.requestor, + event.xselectionrequest.property, + event.xselectionrequest.target, + 8, PropModeReplace, + (unsigned char *)(CurSelectionData ? CurSelectionData : ""), + CurSelectionLen); + notify.xselection.property = event.xselectionrequest.property; + } else if (event.xselectionrequest.selection == XA_PRIMARY && + event.xselectionrequest.target == targets) + { + Atom type = XA_STRING; + + XChangeProperty(display, + event.xselectionrequest.requestor, + event.xselectionrequest.property, + event.xselectionrequest.target, + 32, PropModeReplace, + (unsigned char *)&type, 1); + notify.xselection.property = event.xselectionrequest.property; + } else { + /*fprintf(stderr, + "selection request %ld prop: %ld target: %ld requestor=%lX\n", + event.xselectionrequest.selection, + event.xselectionrequest.property, + event.xselectionrequest.target, + event.xselectionrequest.requestor);*/ + + notify.xselection.property = None; + } + + XSendEvent(display, notify.xselection.requestor, False, 0L, ¬ify); + } + break; + } +} + +static TEvent Pending = { evNone }; + +int ConGetEvent(TEventMask EventMask, TEvent *Event, int WaitTime, int Delete) { + fd_set read_fds; + struct timeval timeout; + int rc; + static TEvent Queued = { evNone }; + + Event->What = evNone; + if (Queued.What != evNone) { + *Event = Queued; + if (Delete) Queued.What = evNone; + if (Event->What & EventMask) return 0; + else Queued.What = evNone; + } + + Event->What = evNone; + if (Pending.What != evNone) { + *Event = Pending; + if (Delete) Pending.What = evNone; + if (Event->What & EventMask) return 0; + else + Pending.What = evNone; + } + + Event->What = evNone; + while (Event->What == evNone) { + Event->What = evNone; + while (XPending(display) > 0) { + ProcessXEvents(Event); + if (Event->What != evNone) { + while ((Event->What == evMouseMove) && (Queued.What == evNone)) { + while ((rc = XPending(display)) > 0) { + ProcessXEvents(&Queued); + if (Queued.What == evMouseMove) { + *Event = Queued; + Queued.What = evNone; + } else break; + } + if (rc <= 0) break; + } + } + if (Delete == 0) + Pending = *Event; + if (Event->What & EventMask) return 0; + else + Pending.What = evNone; + Event->What = evNone; + } + + Event->What = evNone; + FD_ZERO(&read_fds); + FD_SET(ConnectionNumber(display), &read_fds); + for (int p = 0; p < MAX_PIPES; p++) + if (Pipes[p].used) + if (Pipes[p].fd != -1) + FD_SET(Pipes[p].fd, &read_fds); + + if ((WaitTime == -1 || WaitTime > MouseAutoDelay) && (LastMouseEvent.What == evMouseAuto) && (EventMask & evMouse)) { + timeout.tv_sec = 0; + timeout.tv_usec = MouseAutoDelay * 1000; + rc = select(sizeof(fd_set) * 8, + FD_SET_CAST() &read_fds, NULL, NULL, + &timeout); + if (rc == 0) { + *Event = LastMouseEvent; + return 0; + } + } else if ((WaitTime == -1 || WaitTime > MouseAutoRepeat) && (LastMouseEvent.What == evMouseDown || LastMouseEvent.What == evMouseMove) + && + (LastMouseEvent.Mouse.Buttons) && (EventMask & evMouse)) + { + timeout.tv_sec = 0; + timeout.tv_usec = MouseAutoRepeat * 1000; + rc = select(sizeof(fd_set) * 8, + FD_SET_CAST() &read_fds, NULL, NULL, + &timeout); + if (rc == 0) { + LastMouseEvent.What = evMouseAuto; + *Event = LastMouseEvent; + return 0; + } + } else if (WaitTime == -1) { + rc = select(sizeof(fd_set) * sizeof(char), + FD_SET_CAST() &read_fds, NULL, NULL, + NULL); + } else { + timeout.tv_sec = 0; + timeout.tv_usec = WaitTime * 1000 + 1; + rc = select(sizeof(fd_set) * sizeof(char), + FD_SET_CAST() &read_fds, NULL, NULL, + &timeout); + } + + if (rc == 0 || rc == -1) { + Event->What = evNone; + return -1; + } + if (FD_ISSET(ConnectionNumber(display), &read_fds)) // X has priority + continue; + for (int pp = 0; pp < MAX_PIPES; pp++) { + if (Pipes[pp].used) + if (Pipes[pp].fd != -1) + if (FD_ISSET(Pipes[pp].fd, &read_fds)) { + if (Pipes[pp].notify) { + Event->What = evNotify; + Event->Msg.View = 0; + Event->Msg.Model = Pipes[pp].notify; + Event->Msg.Command = cmPipeRead; + Event->Msg.Param1 = pp; + Pipes[pp].stopped = 0; + } + //fprintf(stderr, "Pipe %d\n", Pipes[pp].fd); + return 0; + } + } + } + return 0; +} + +int ConPutEvent(TEvent Event) { + Pending = Event; + return 0; +} + +int ConFlush(void) { + XFlush(display); + return 0; +} + +int ConGrabEvents(TEventMask EventMask) { + return 0; +} + +int GetXSelection(int *len, char **data) { + if (CurSelectionOwn) { + *data = (char *) malloc(CurSelectionLen); + if (*data == 0) + return -1; + memcpy(*data, CurSelectionData, CurSelectionLen); + *len = CurSelectionLen; + return 0; + } else { + if (XGetSelectionOwner(display, XA_PRIMARY) != None) { + XEvent event; + Atom type; + long extra; + int i; + long l; + time_t time_started; + + assert(selection_buffer != None); + + XConvertSelection(display, + XA_PRIMARY, XA_STRING, + selection_buffer, win, now); + + time_started = time(NULL); + + for (;;) { + if (XCheckTypedWindowEvent(display, + win, + SelectionNotify, + &event)) + break; + + time_t now = time(NULL); + + if (time_started > now) + time_started = now; + + if (now - time_started > 5000) + return -1; + } + + /*do + { + XNextEvent(display, &event); + } while (event.type != SelectionNotify && + event.xselection.property != None && + event.type != ButtonPress);*/ + + if (event.type == SelectionNotify + && event.xselection.property != None) { + XGetWindowProperty(display, + event.xselection.requestor, + event.xselection.property, + 0L, 0x10000, True, + event.xselection.target, &type, &i, + (unsigned long *)&l, + (unsigned long *)&extra, + (unsigned char **)data); + + *len = l; + return 0; + } + return -1; + } + } + *data = XFetchBytes(display, len); + if (*data == 0) + return -1; + else + return 0; +} + +int SetXSelection(int len, char *data) { + if (CurSelectionData != 0) { + free(CurSelectionData); + } + CurSelectionData = (char *)malloc(len); + if (CurSelectionData == 0) { + CurSelectionLen = 0; + return -1; + } + CurSelectionLen = len; + memcpy(CurSelectionData, data, CurSelectionLen); + if (CurSelectionLen < 64 * 1024) { + XStoreBytes(display, data, len); + XSetSelectionOwner(display, XA_PRIMARY, win, CurrentTime); + if (XGetSelectionOwner(display, XA_PRIMARY) == win) + CurSelectionOwn = 1; + } else { + XSetSelectionOwner(display, XA_PRIMARY, None, CurrentTime); + } + return 0; +} + +GUI::GUI(int &argc, char **argv, int XSize, int YSize) { + int o = 1; + + for (int c = 1; c < argc; c++) { + if (strcmp(argv[c], "-font") == 0) { + if (c + 1 < argc) { + strcpy(WindowFont, argv[++c]); + } + } else if (strcmp(argv[c], "-geometry") == 0) { + if (c + 1 < argc) { + + XParseGeometry(argv[++c], &initX, &initY, + &ScreenCols, &ScreenRows); + if (ScreenCols > 255) + ScreenCols = 255; + else if (ScreenCols < MIN_SCRWIDTH) + ScreenCols = MIN_SCRWIDTH; + if (ScreenRows > 255) + ScreenRows = 255; + else if (ScreenRows < MIN_SCRHEIGHT) + ScreenRows = MIN_SCRHEIGHT; + setUserPosition = 1; + } + } else if ((strcmp(argv[c], "-noxmb") == 0) + || (strcmp(argv[c], "--noxmb") == 0)) + useXMB = 0; + else + argv[o++] = argv[c]; + } + argc = o; + argv[argc] = 0; + + if (SetupXWindow(argc, argv) == 0 && + ::ConInit(XSize, YSize) == 0) + gui = this; + else + gui = NULL; + fArgc = argc; + fArgv = argv; +} + +GUI::~GUI() { + ::ConDone(); +} + +int GUI::ConSuspend(void) { + return ::ConSuspend(); +} + +int GUI::ConContinue(void) { + return ::ConContinue(); +} + +int GUI::ShowEntryScreen() { + return 1; +} + +int GUI::OpenPipe(char *Command, EModel *notify) { +#ifndef NO_PIPES + int i; + + for (i = 0; i < MAX_PIPES; i++) { + if (Pipes[i].used == 0) { + int pfd[2]; + + Pipes[i].id = i; + Pipes[i].notify = notify; + Pipes[i].stopped = 1; + + if (pipe((int *)pfd) == -1) + return -1; + + switch (Pipes[i].pid = fork()) { + case -1: /* fail */ + return -1; + case 0: /* child */ + signal(SIGPIPE, SIG_DFL); + close(pfd[0]); + close(0); + assert(open("/dev/null", O_RDONLY) == 0); + dup2(pfd[1], 1); + dup2(pfd[1], 2); + close(pfd[1]); + exit(system(Command)); + default: + close(pfd[1]); + fcntl(pfd[0], F_SETFL, O_NONBLOCK); + Pipes[i].fd = pfd[0]; + } + Pipes[i].used = 1; + //fprintf(stderr, "Pipe Open: %d\n", i); + return i; + } + } + return -1; +#else + return 0; +#endif +} + +int GUI::SetPipeView(int id, EModel *notify) { +#ifndef NO_PIPES + if (id < 0 || id > MAX_PIPES) + return -1; + if (Pipes[id].used == 0) + return -1; + //fprintf(stderr, "Pipe View: %d %08X\n", id, notify); + Pipes[id].notify = notify; +#endif + return 0; +} + +int GUI::ReadPipe(int id, void *buffer, int len) { +#ifndef NO_PIPES + int rc; + + if (id < 0 || id > MAX_PIPES) + return -1; + if (Pipes[id].used == 0) + return -1; + //fprintf(stderr, "Pipe Read: Get %d %d\n", id, len); + + rc = read(Pipes[id].fd, buffer, len); + //fprintf(stderr, "Pipe Read: Got %d %d\n", id, len); + if (rc == 0) { + close(Pipes[id].fd); + Pipes[id].fd = -1; + return -1; + } + if (rc == -1) { + Pipes[id].stopped = 1; + return 0; + } + return rc; +#else + return 0; +#endif +} + +int GUI::ClosePipe(int id) { +#ifndef NO_PIPES + int status; + + if (id < 0 || id > MAX_PIPES) + return -1; + if (Pipes[id].used == 0) + return -1; + if (Pipes[id].fd != -1) + close(Pipes[id].fd); + kill(Pipes[id].pid, SIGHUP); + alarm(2); + waitpid(Pipes[id].pid, &status, 0); + alarm(0); + //fprintf(stderr, "Pipe Close: %d\n", id); + Pipes[id].used = 0; + return WEXITSTATUS(status); +#else + return 0; +#endif +} + +int GUI::RunProgram(int mode, char *Command) { + char Cmd[1024]; + + char const* xterm = getenv("TERM"); + if (NULL == xterm || 0 == *xterm) + xterm = "xterm"; + + strcpy(Cmd, xterm); + + if (*Command == 0) // empty string = shell + strcat(Cmd, " -ls &"); + else { + strcat(Cmd, " -e "); + // buffer overflow problem: -2 for possible async. + strncat(Cmd, Command, sizeof(Cmd) - strlen(Cmd) - 2); + Cmd[sizeof(Cmd) - 3] = 0; + if (mode == RUN_ASYNC) + strcat(Cmd, " &"); + } + rc = system(Cmd); + return rc; +} + +char ConGetDrawChar(int index) { + static char tab[] = "\x0D\x0C\x0E\x0B\x12\x19____+>\x1F\x01\x12 "; + + assert(index >= 0 && index < (int) strlen(tab)); + + return tab[index]; +} diff --git a/src/conkbd.h b/src/conkbd.h new file mode 100644 index 0000000..a1714c1 --- /dev/null +++ b/src/conkbd.h @@ -0,0 +1,77 @@ +/* conkbd.h + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#ifndef __CONKBD_H__ +#define __CONKBD_H__ + +#define kfAltXXX 0x01000000L +#define kfModifier 0x02000000L +#define kfSpecial 0x00010000L +#define kfAlt 0x00100000L +#define kfCtrl 0x00200000L +#define kfShift 0x00400000L +#define kfGray 0x00800000L +#define kfKeyUp 0x10000000L +#define kfAll 0x00F00000L + +#define isAltXXX(x) (((x) & (kfAltXXX)) != 0) +#define isAlt(x) (((x) & kfAlt) != 0) +#define isCtrl(x) (((x) & kfCtrl) != 0) +#define isShift(x) (((x) & kfShift) != 0) +#define isGray(x) (((x) & kfGray) != 0) +#define keyType(x) ((x) & kfAll) +#define keyCode(x) ((x) & 0x000FFFFF) +#define kbCode(x) (((x) & 0x0FFFFFFF) & ~(kfGray | kfAltXXX)) +#define isAscii(x) ((((x) & (kfAlt | kfCtrl)) == 0) && (keyCode(x) < 256)) + +#define kbF1 (kfSpecial | 0x101) +#define kbF2 (kfSpecial | 0x102) +#define kbF3 (kfSpecial | 0x103) +#define kbF4 (kfSpecial | 0x104) +#define kbF5 (kfSpecial | 0x105) +#define kbF6 (kfSpecial | 0x106) +#define kbF7 (kfSpecial | 0x107) +#define kbF8 (kfSpecial | 0x108) +#define kbF9 (kfSpecial | 0x109) +#define kbF10 (kfSpecial | 0x110) +#define kbF11 (kfSpecial | 0x111) +#define kbF12 (kfSpecial | 0x112) + +#define kbUp (kfSpecial | 0x201) +#define kbDown (kfSpecial | 0x202) +#define kbLeft (kfSpecial | 0x203) +#define kbCenter (kfSpecial | 0x204) +#define kbRight (kfSpecial | 0x205) +#define kbHome (kfSpecial | 0x206) +#define kbEnd (kfSpecial | 0x207) +#define kbPgUp (kfSpecial | 0x208) +#define kbPgDn (kfSpecial | 0x209) +#define kbIns (kfSpecial | 0x210) +#define kbDel (kfSpecial | 0x211) + +#define kbSpace 32 + +#define kbBackSp (kfSpecial | 8) +#define kbTab (kfSpecial | 9) +#define kbEnter (kfSpecial | 13) +#define kbEsc (kfSpecial | 27) + +#define kbAlt (kfModifier | 0x301) +#define kbCtrl (kfModifier | 0x302) +#define kbShift (kfModifier | 0x303) +#define kbCapsLock (kfModifier | 0x304) +#define kbNumLock (kfModifier | 0x305) +#define kbScrollLock (kfModifier | 0x306) + +#define kbPause (kfSpecial | 0x401) +#define kbPrtScr (kfSpecial | 0x402) +#define kbSysReq (kfSpecial | 0x403) +#define kbBreak (kfSpecial | 0x404) + +#endif diff --git a/src/console.h b/src/console.h new file mode 100644 index 0000000..b115871 --- /dev/null +++ b/src/console.h @@ -0,0 +1,211 @@ +/* console.h + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#ifndef __CONSOLE_H__ +#define __CONSOLE_H__ + +/* don't change these, used as index */ +#define DCH_C1 0 +#define DCH_C2 1 +#define DCH_C3 2 +#define DCH_C4 3 +#define DCH_H 4 +#define DCH_V 5 +#define DCH_M1 6 +#define DCH_M2 7 +#define DCH_M3 8 +#define DCH_M4 9 +#define DCH_X 10 +#define DCH_RPTR 11 +#define DCH_EOL 12 +#define DCH_EOF 13 +#define DCH_END 14 +#define DCH_AUP 15 +#define DCH_ADOWN 16 +#define DCH_HFORE 17 +#define DCH_HBACK 18 +#define DCH_ALEFT 19 +#define DCH_ARIGHT 20 + +#define ConMaxCols 256 +#define ConMaxRows 128 + +#define csUp 0 +#define csDown 1 +#define csLeft 2 +#define csRight 3 + +#define evNone 0 +#define evKeyDown 0x0001 +#define evKeyUp 0x0002 +#define evMouseDown 0x0010 +#define evMouseUp 0x0020 +#define evMouseMove 0x0040 +#define evMouseAuto 0x0080 +#define evCommand 0x0100 +#define evBroadcast 0x0200 +#define evNotify 0x0400 + +#define evKeyboard (evKeyDown | evKeyUp) +#define evMouse (evMouseDown | evMouseUp | evMouseMove | evMouseAuto) +#define evMessage (evCommand | evBroadcast) + +#include "conkbd.h" + +#define cmRefresh 1 +#define cmResize 2 +#define cmClose 3 +#define cmPipeRead 4 +#define cmMainMenu 5 +#define cmPopupMenu 6 + +/* vertical scroll */ + +#define cmVScrollUp 10 +#define cmVScrollDown 11 +#define cmVScrollPgUp 12 +#define cmVScrollPgDn 13 +#define cmVScrollMove 14 + +/* horizontal scroll */ + +#define cmHScrollLeft 15 +#define cmHScrollRight 16 +#define cmHScrollPgLt 17 +#define cmHScrollPgRt 18 +#define cmHScrollMove 19 + +#define cmDroppedFile 30 +#define cmRenameFile 31 /* TODO: in-place editing of titlebar */ + +typedef unsigned char TAttr; +typedef TAttr *PAttr; + +#ifdef NTCONSOLE +typedef unsigned long TCell; +#else +typedef unsigned short TCell; +#endif + +typedef TCell *PCell; +typedef TCell TDrawBuffer[ConMaxCols]; +typedef TDrawBuffer *PDrawBuffer; +typedef unsigned long TEventMask; +typedef unsigned long TKeyCode; +typedef unsigned long TCommand; + +class EModel; // forward +class GView; + +typedef struct { + TEventMask What; + GView *View; + TKeyCode Code; +} TKeyEvent; + +typedef struct { + TEventMask What; + GView *View; + long X; + long Y; + unsigned short Buttons; + unsigned short Count; + TKeyCode KeyMask; +} TMouseEvent; + +typedef struct { + TEventMask What; + GView *View; + EModel *Model; + TCommand Command; + long Param1; + void *Param2; +} TMsgEvent; + +typedef union { + TEventMask What; + TKeyEvent Key; + TMouseEvent Mouse; + TMsgEvent Msg; + char fill[32]; +} TEvent; + +#define SUBMENU_NORMAL (-1) +#define SUBMENU_CONDITIONAL (-2) + +typedef struct _mItem { + char *Name; + char *Arg; + int SubMenu; + int Cmd; +} mItem; + +typedef struct _mMenu { + char *Name; + int Count; + mItem *Items; +} mMenu; + +extern int MenuCount; +extern mMenu *Menus; + +int ConInit(int XSize, int YSize); +int ConDone(); +int ConSuspend(); +int ConContinue(); +int ConSetTitle(char *Title, char *STitle); +int ConGetTitle(char *Title, int MaxLen, char *STitle, int SMaxLen); + +int ConClear(); +int ConPutBox(int X, int Y, int W, int H, PCell Cell); +int ConGetBox(int X, int Y, int W, int H, PCell Cell); +int ConPutLine(int X, int Y, int W, int H, PCell Cell); +int ConSetBox(int X, int Y, int W, int H, TCell Cell); +int ConScroll(int Way, int X, int Y, int W, int H, TAttr Fill, int Count); + +int ConSetSize(int X, int Y); +int ConQuerySize(int *X, int *Y); + +int ConSetCursorPos(int X, int Y); +int ConQueryCursorPos(int *X, int *Y); +int ConShowCursor(); +int ConHideCursor(); +int ConCursorVisible(); +int ConSetCursorSize(int Start, int End); + +int ConSetMousePos(int X, int Y); +int ConQueryMousePos(int *X, int *Y); +int ConShowMouse(); +int ConHideMouse(); +int ConMouseVisible(); +int ConQueryMouseButtons(int *ButtonCount); + +int ConGetEvent(TEventMask EventMask, TEvent *Event, int WaitTime, int Delete); +int ConPutEvent(TEvent Event); + +void MoveCh(PCell B, char Ch, TAttr Attr, int Count); +void MoveChar(PCell B, int Pos, int Width, const char Ch, TAttr Attr, int Count); +void MoveMem(PCell B, int Pos, int Width, const char* Ch, TAttr Attr, int Count); +void MoveStr(PCell B, int Pos, int Width, const char* Ch, TAttr Attr, int MaxCount); +void MoveCStr(PCell B, int Pos, int Width, const char* Ch, TAttr A0, TAttr A1, int MaxCount); +void MoveAttr(PCell B, int Pos, int Width, TAttr Attr, int Count); +void MoveBgAttr(PCell B, int Pos, int Width, TAttr Attr, int Count); + +int CStrLen(const char *s); + +int NewMenu(const char *Name); +int NewItem(int menu, const char *Name); +int NewSubMenu(int menu, const char *Name, int submenu, int type); +int GetMenuId(const char *Name); + +char ConGetDrawChar(int index); + +extern char WindowFont[64]; + +#endif diff --git a/src/defcfg.fte b/src/defcfg.fte new file mode 100644 index 0000000..8de121b --- /dev/null +++ b/src/defcfg.fte @@ -0,0 +1,517 @@ +menu File { + item "&Open...\tF3" { FileOpen } + item "&Reload\tShift+F3" { FileReload } + item "&Save\tF2" { FileSave } + item "Save &As...\tShift+F2" { FileSaveAs } + item "Save Al&l\tCtrl+F2" { FileSaveAll } + item "&Close\tAlt+Q" { FileClose } + item; + item "&Next\tAlt+Left" { FileNext } + item "&Previous\tAlt+Right" { FilePrev } + item; + item "E&xit\tAlt+X" { ExitEditor } +} + +menu Edit { + item "&Undo\tAlt+BackSp" { Undo } + item "&Redo\tAlt+Shift+BackSp" { Redo } + item; + item "Cu&t\tShift+Del" { BlockCut } + item "&Copy\tCtrl+Ins" { BlockCopy } + item "&Paste\tShift+Ins" { BlockPasteStream } + item "P&aste Column\tAlt+Ins" { BlockPasteColumn } + item; + item "&Delete line\tCtrl+Y" { KillLine } + item "&Split line\tCtrl+L" { LineSplit } + item "&Join line\tCtrl+J" { LineJoin } + item; + item "&Quote Literal...\tCtrl+Q" { InsertChar } +} + +menu Translate { + item "Upperc&ase" { BlockCaseUp } + item "Low&ercase" { BlockCaseDown } + item "Tog&glecase" { BlockCaseToggle } +} + +menu Block { + item "&Unmark\tEsc" { BlockUnmark } + item "Mark &Line\tAlt+L" { BlockMarkLine } + item "Mark &Stream\tAlt+A" { BlockMarkStream } + item "Mark &Column\tAlt+K" { BlockMarkColumn } + item; + item "&Indent\tAlt+I" { BlockIndent } + item "U&nindent\tAlt+U" { BlockUnindent } + item; + item "&Write..." { BlockWrite } + item "&Read..." { BlockRead } + item "&Print" { BlockPrint } + item; + submenu "Translat&e", Translate; +} + +menu Search { + item "&Find...\tCtrl+F" { Find } + item "Find and &replace...\tCtrl+R" { FindReplace } + item "Repeat &Last find\tCtrl+L" { FindRepeat } + item "Repeat last find re&verse\tCtrl+B" { FindRepeatReverse } + item "Repeat last find &once\tCtrl+N" { FindRepeatOnce } + item "Incremental &search\tCtrl+S" { IncrementalSearch } + item; + item "&Place Bookmark..." { PlaceBookmark } + item "Goto &Bookmark..." { GotoBookmark } + item; + item "&Match paren\tAlt+-" { MatchBracket } + item "&Goto line...\tAlt+J" { MoveToLine } +} + +menu Tools { + item "&Compile\tF9" { Compile "make -k " } + item "&Grep" { Compile "grep -n " } + item; + item "Sh&ell" { RunProgram "" } + item; + item "Go to prev &error\tF11" { CompilePrevError } + item "Go to &next error\tF12" { CompileNextError } + item; + item "&Messages\tS+F9" { ViewMessages } +} + +menu Window { + item "Split &Horizontal\tShift+F2" { WinHSplit } + item "&Close view\tCtrl+Alt+F4" { WinClose } + item "Close &other views\tF5" { WinZoom } + item; + item "&Routines\tCtrl+I" { ListRoutines } + item "&Buffers\tAlt+0" { ViewBuffers } + item "&Directory\tC+M" { DirOpen } +} + +menu Options { + item "&Insert mode\tC+O C+I" { ToggleInsert } + item "&Auto indent\tC+O C+A" { ToggleAutoIndent } + item "&Case sensitive\tC+O C+C" { ToggleMatchCase } + item "Trim &EOL spaces\tC+O C+E" { ToggleTrim } + item "&Read only\tC+O C+R" { ToggleReadOnly } + item "&Undo/Redo\tC+O C+U" { ToggleUndo } + item "&Show markers\tC+O C+." { ToggleShowMarkers; WinRefresh } + item; + item "&Word wrap\tC+O C+W" { ToggleWordWrap } + item "&Left margin...\tC+O A+[" { ChangeLeftMargin } + item "Ri&ght margin...\tC+O A+]" { ChangeRightMargin } + item; + item "&Tab size...\tC+O C+T" { ChangeTabSize; WinRefresh } + item "S&how tabs\tC+O Tab" { ToggleShowTabs; WinRefresh } + item "E&xpand tabs\tC+O C+Tab" { ToggleExpandTabs; WinRefresh } + item "&Print to... " { SetPrintDevice } +} + +menu Help { + item "&About..." { ShowVersion } +} + +menu Main { + submenu "&File", File; + submenu "&Edit", Edit; + submenu "&Block", Block; + submenu "&Search", Search; + submenu "&Tools", Tools; + submenu "&Window", Window; + submenu "&Options", Options; + submenu "&Help", Help; +} + +menu Local { + item "&Unmark\tEsc" { BlockUnmark } + item "Cu&t\tShift+Del" { BlockCut } + item "&Copy\tCtrl+Ins" { BlockCopy } + item "&Paste\tShift+Ins" { BlockPasteStream } + item "P&aste Column\tAlt+Ins" { BlockPasteColumn } + item; + item "Delete &line\tCtrl+Y" { KillLine } + item "Delete to &EOL\tAlt+End" { KillToLineEnd } + item; + item "&Save\tF2" { FileSave } + item "Cl&ose\tAlt+Q" { FileClose } +} + +eventmap MODEL { # basic commands, for files, directories, message view, etc. + key [C+F2] { FileSaveAll } + key [F3] { FileOpen } + key [F4] { WinNext } + key [C+F4] { WinHSplit } + key [S+F4] { WinPrev } + key [A+S-F4] { WinClose } + key [F5] { WinZoom } + key [F6] { FileNext } + key [S+F6] { FilePrev } + key [A+S-F6] { FileLast } + key [F10] { MainMenu } + key [C+F9] { RunProgram } + key [S+F10] { LocalMenu } + + key [A+G-Up] { WinPrev } + key [A+G-Down] { WinNext } + key [A+G-Left] { FilePrev } + key [A+G-Right] { FileNext } + + key [A+G-PgUp] { WinPrev; MovePageUp; WinNext } + key [A+G-PgDn] { WinNext; MovePageDown; WinPrev } + key [A+C+G-PgUp] { WinNext; MovePageUp; WinPrev } + key [A+C+G-PgDn] { WinPrev; MovePageDown; WinNext } + + key [A+Q] { FileClose } + key [A+X] { ExitEditor } + + key [C+S+G-Up] { WinResize -1 } + key [C+S+G-Down] { WinResize +1 } + + # this is also useful for 'grep -n' etc. if configured + key [F9] { Compile; ViewMessages } + key [F11] { CompilePrevError } + key [F12] { CompileNextError } + key [S+F9] { ViewMessages } + + key [A+0] { ViewBuffers } + key [A+1] { SwitchTo 1 } + key [A+2] { SwitchTo 2 } + key [A+3] { SwitchTo 3 } + key [A+4] { SwitchTo 4 } + key [A+5] { SwitchTo 5 } + key [A+6] { SwitchTo 6 } + key [A+7] { SwitchTo 7 } + key [A+8] { SwitchTo 8 } + key [A+9] { SwitchTo 9 } +} + +eventmap PLAIN: MODEL { +# keymap for plaintext mode + MainMenu = 'Main'; # menu for menubar + LocalMenu = 'Local'; # local menu + + key [Esc] { BlockMarkStream; BlockUnmark } + key [F2] { FileSave } + key [S+F2] { FileSaveAs } + key [A+S-F2] { FileSave; FileClose } + key [S+F3] { FileReload; WinRefresh } + key [C+F3] { FileOpenInMode } + key [F7] { BlockBegin } + key [S+F7] { MoveBlockStart } + key [F8] { BlockEnd } + key [S+F8] { MoveBlockEnd } + key [G-Left] { MoveLeft } + key [C+G-Left] { MoveWordPrev } + key [G-Right] { MoveRight } + key [C+G-Right] { MoveWordNext } + key [G-Up] { MoveUp } + key [G-Down] { MoveDown } + key [G-Home] { MoveLineStart } + key [C+G-Home] { MovePageStart } + key [G-End] { MoveLineEnd } + key [C+G-End] { MovePageEnd } + key [G-PgUp] { MovePageUp } + key [C+G-PgUp] { MoveFileStart } + key [G-PgDn] { MovePageDown } + key [C+G-PgDn] { MoveFileEnd } +# key [A+G-Up] { ScrollUp } +# key [A+G-Down] { ScrollDown } +# key [A+G-Left] { ScrollLeft } +# key [A+G-Right] { ScrollRight } + + key [S+G-Left] { BlockExtendBegin; MoveLeft; BlockExtendEnd } + key [S+G-Right] { BlockExtendBegin; MoveRight; BlockExtendEnd } + +# key [G+0] { ToggleInsert } +# key [G+S+0] { InsertString 'foo' } + + key [C+G-S+Left] { BlockExtendBegin; MoveWordPrev; BlockExtendEnd } + key [C+G-S+Right] { BlockExtendBegin; MoveWordNext; BlockExtendEnd } + key [G-S+Up] { BlockExtendBegin; MoveUp; BlockExtendEnd } + key [G-S+Down] { BlockExtendBegin; MoveDown; BlockExtendEnd } + key [G-S+Home] { BlockExtendBegin; MoveLineStart; BlockExtendEnd } + key [G-S+End] { BlockExtendBegin; MoveLineEnd; BlockExtendEnd } + key [C+G-S+Home] { BlockExtendBegin; MovePageStart; BlockExtendEnd } + key [C+G-S+End] { BlockExtendBegin; MovePageEnd; BlockExtendEnd } + key [G-S+PgUp] { BlockExtendBegin; MovePageUp; BlockExtendEnd } + key [G-S+PgDn] { BlockExtendBegin; MovePageDown; BlockExtendEnd } + key [C+G-S+PgUp] { BlockExtendBegin; MoveFileStart; BlockExtendEnd } + key [C+G-S+PgDn] { BlockExtendBegin; MoveFileEnd; BlockExtendEnd } + key [A+G-S+Up] { BlockExtendBegin; ScrollUp; BlockExtendEnd } + key [A+G-S+Down] { BlockExtendBegin; ScrollDown; BlockExtendEnd } + key [A+G-S+Left] { BlockExtendBegin; ScrollLeft; BlockExtendEnd } + key [A+G-S+Right] { BlockExtendBegin; ScrollRight; BlockExtendEnd } + key [A+G-C+Up] { MovePrevEqualIndent } + key [A+G-C+Down] { MoveNextEqualIndent } + key [A+G-C+Left] { MovePrevTab } + key [A+G-C+Right] { MoveNextTab } + key [C+G-Ins] { BlockCopy } + key [C+G-Del] { BlockKill } + key [S+G-Ins] { BlockPasteStream } + key [S+G-Del] { BlockCut } + key [A+G-Ins] { BlockPasteColumn } + key [A+G-S+Ins] { BlockPasteLine } + key [G-Enter] { LineNew } + key [BackSp] { BackSpace } + key [G-Ins] { ToggleInsert } + key [G-Del] { Delete } + key [Tab] { InsertTab } + key [S+Tab] { InsertSpacesToTab 10 } + key [C+Tab] { CompleteWord } +# key [C+Tab] { InsertTab } + key [C+BackSp] { KillWordPrev } + key [C+S+BackSp] { KillToLineStart } + key [C+G-Enter] { LineSplit } + key [G-S+Enter] { LineInsert } + key [A+G-Enter] { LineAdd } + key [A+G-Del] { KillWord } + key [A+G-End] { KillToLineEnd } + key [A+BackSp] { Undo } + key [A+S+BackSp] { Redo } + + key [C+A_1] { GotoBookmark "1" } + key [C+A_2] { GotoBookmark "2" } + key [C+A_3] { GotoBookmark "3" } + key [C+A_4] { GotoBookmark "4" } + key [C+A_5] { GotoBookmark "5" } + key [C+A_6] { GotoBookmark "6" } + key [C+A_7] { GotoBookmark "7" } + key [C+A_8] { GotoBookmark "8" } + key [C+A_9] { GotoBookmark "9" } + key [C+A_0] { GotoBookmark "0" } + + key [C+P_1] { PlaceBookmark "1" } + key [C+P_2] { PlaceBookmark "2" } + key [C+P_3] { PlaceBookmark "3" } + key [C+P_4] { PlaceBookmark "4" } + key [C+P_5] { PlaceBookmark "5" } + key [C+P_6] { PlaceBookmark "6" } + key [C+P_7] { PlaceBookmark "7" } + key [C+P_8] { PlaceBookmark "8" } + key [C+P_9] { PlaceBookmark "9" } + key [C+P_0] { PlaceBookmark "0" } + + key [C+B] { FindRepeatReverse } + key [C+C] { MoveToColumn } + key [C+D] { LineDuplicate } + key [C+F] { Find } + key [C+I] { ListRoutines } + key [C+J] { LineJoin } + key [C+L] { FindRepeat } + key [C+M] { DirOpen } + key [C+N] { FindRepeatOnce } + key [C+Q] { InsertChar } + key [C+R] { FindReplace } + key [C+T] { KillWord } + key [C+Y] { KillLine } + key [C+E] { LineTrim } + key [A+A] { BlockMarkStream } + key [A+B] { MainMenu 'B' } + key [A+C] { BlockCopy } + key [A+D] { MainMenu 'D' } + key [A+E] { MainMenu 'E' } + key [A+F] { MainMenu 'F' } + key [A+G] { BlockCut } + key [A+H] { MainMenu 'H' } + key [A+I] { BlockIndent } + key [A+J] { MoveToLine } + key [A+K] { BlockMarkColumn } + key [A+L] { BlockMarkLine } + key [A+O] { MainMenu 'O' } + key [A+R] { WrapPara } # Reformat + key [A+S] { MainMenu 'S' } + key [A+T] { MainMenu 'T' } + key [A+U] { BlockUnindent } + key [A+W] { MainMenu 'W' } + key [C+S] { IncrementalSearch } + + key [C+O_C+A] { ToggleAutoIndent } + key [C+O_C+C] { ToggleMatchCase } + key [C+O_C+E] { ToggleTrim } + key [C+O_C+I] { ToggleInsert } +# key [C+O_C+M] { ChangeMode } +# key [C+O_C+M] { ShowMenu 'MChangeMode' } + key [C+O_C+R] { ToggleReadOnly } + key [C+O_C+S] { ToggleSysClipboard } + key [C+O_C+T] { ChangeTabSize } + key [C+O_C+U] { ToggleUndo } + key [C+O_C+W] { ToggleWordWrap } + key [C+O_.] { ToggleShowMarkers } + key [C+O_[] { SetLeftMargin } + key [C+O_\]] { SetRightMargin } + key [C+O_A+[] { ChangeLeftMargin } + key [C+O_A+\]] { ChangeRightMargin } + key [C+O_Tab] { ToggleShowTabs } + key [C+O_C+Tab] { ToggleExpandTabs } + key [C+O_Del] { ToggleDeleteKillTab } + key [C+O_G-Ins] { ToggleInsert } + key [C+O_BackSp] { ToggleBackSpKillTab } + key [C+O_Space] { ToggleIndentWithTabs } + key [C+O_C+BackSp] { ToggleBackSpUnindents } + key [A+-] { MatchBracket } + key [A+=] { HilitMatchBracket } + key [C+Space] { InsPrevLineChar } + key [A+Space] { InsPrevLineToEol } + key [A+F5] { ShowEntryScreen } + key [C+_] { ShowPosition } + key [Center] { MoveLineCenter } + key [C+X] { MovePrevPos } +# key [C+S+A] { ASCIITable } + key [G+*] { LineInsert ; MoveUp; ScrollUp } + +# key [G++] { DumpFold } + key [A+G++] { FoldCreate } + key [A+G+-] { FoldDestroy } + key [G+S++] { FoldPromote } + key [G+S+-] { FoldDemote } + key [C+G++] { FoldOpen } + key [C+G+-] { FoldClose } + key [C+G+*] { FoldOpenNested } + key [C+G+/] { FoldToggleOpenClose } + key [A+G+*] { FoldOpenAll } + key [A+G+/] { FoldCloseAll } + +# key [C+G-Up] { MoveFoldPrev } +# key [C+G-Down] { MoveFoldNext } + +# key [A+C+A] { FileOpen 'BUFFER.CPP' } + + key [C+K] { ShowKey } + key [A+,] { SearchWordPrev } + key [A+.] { SearchWordNext } + key [A+/] { HilitWord } +} + +colorize PLAIN { + SyntaxParser = 'PLAIN'; + + color { + { 'Normal', '7 0' }, + }; +} + +mode PLAIN { + Colorizer = 'PLAIN'; +} + +eventmap LIST { + key [G-Left] { MoveLeft } + key [G-Right] { MoveRight } + key [G-Up] { MoveUp } + key [G-Down] { MoveDown } + key [G-Home] { MoveLineStart } + key [C+G-Home] { MovePageStart } + key [G-End] { MoveLineEnd } + key [C+G-End] { MovePageEnd } + key [G-PgUp] { MovePageUp } + key [C+G-PgUp] { MoveFileStart } + key [G-PgDn] { MovePageDown } + key [C+G-PgDn] { MoveFileEnd } + key [A+G-Up] { ScrollUp } + key [A+G-Down] { ScrollDown } + key [A+G-Left] { ScrollLeft } + key [A+G-Right] { ScrollRight } + + key [Esc] { Cancel } + key [G-Enter] { Activate } +} + +eventmap BUFFERS: LIST { + key [C+F10] { FileClose } + key [F2] { FileSave } +} + +eventmap ROUTINES: LIST { +} + +eventmap MLIST: MODEL { + key [G-Left] { MoveLeft } + key [G-Right] { MoveRight } + key [G-Up] { MoveUp } + key [G-Down] { MoveDown } + key [G-Home] { MoveLineStart } + key [C+G-Home] { MovePageStart } + key [G-End] { MoveLineEnd } + key [C+G-End] { MovePageEnd } + key [G-PgUp] { MovePageUp } + key [C+G-PgUp] { MoveFileStart } + key [G-PgDn] { MovePageDown } + key [C+G-PgDn] { MoveFileEnd } +# key [A+G-Up] { ScrollUp } +# key [A+G-Down] { ScrollDown } +# key [A+G-Left] { ScrollLeft } +# key [A+G-Right] { ScrollRight } + + key [G-Enter] { Activate } +} + +menu Directory { + item "&Next\tF6" { FileNext } + item "&Previous\tShift+F6" { FilePrev } + item; + item "&Close\tAlt+Q" { FileClose } + item; + item "E&xit\tAlt+X" { ExitEditor } +} + +menu Navigate { + item "Go &< level\tCtrl+PgUp" { DirGoUp } + item "Go &> level\tCtrl+PgDn" { DirGoDown } + item "Go to &\\\tCtrl+\\" { DirGoRoot } +# item "&/ Goto Dir\t/" { DirGoto } + item "&\\ Goto Dir\t\\" { DirGoto } + item; + item '&A:\\' { DirGoto 'A:\\' } + item '&B:\\' { DirGoto 'B:\\' } + item '&C:\\' { DirGoto 'C:\\' } + item '&D:\\' { DirGoto 'D:\\' } + item '&E:\\' { DirGoto 'E:\\' } + item '&F:\\' { DirGoto 'F:\\' } + item '&G:\\' { DirGoto 'G:\\' } + item '&H:\\' { DirGoto 'H:\\' } + item '&I:\\' { DirGoto 'I:\\' } +} + +menu DirMain { + submenu "&Directory", Directory; + submenu "&Navigate", Navigate; + submenu "&Tools", Tools; + submenu "&Window", Window; +} + +eventmap DIRECTORY: MLIST { + MainMenu = 'DirMain'; + + key [C+G-PgUp] { DirGoUp } + key [C+G-PgDn] { DirGoDown } + key [C+\\] { DirGoRoot } + key [/] { DirGoto } + key [\\] { DirGoto } + key [C+D] { DeleteFile } + + key [A+D] { MainMenu 'D' } + key [A+N] { MainMenu 'N' } + key [A+W] { MainMenu 'W' } +} + +menu Messages { + item "&Close\tAlt+Q" { FileClose } + item; + item "&Next\tF6" { FileNext } + item "&Previous\tShift+F6" { FilePrev } + item; + item "E&xit\tAlt+X" { ExitEditor } +} + +menu MsgMain { + submenu "&Messages", Messages; + submenu "&Tools", Tools; + submenu "&Window", Window; +} + +eventmap MESSAGES: MLIST { + MainMenu = "MsgMain"; + + key [A+M] { MainMenu 'M' } + key [A+T] { MainMenu 'T' } + key [A+W] { MainMenu 'W' } +} diff --git a/src/defcfg2.fte b/src/defcfg2.fte new file mode 100644 index 0000000..3355be3 --- /dev/null +++ b/src/defcfg2.fte @@ -0,0 +1,264 @@ +menu File { + item "&Open...\tCtrl+O" { FileOpen } + item "&Reload" { FileReload } + item "&Save\tCtrl+S" { FileSave } + item "Save &As..." { FileSaveAs } + item "Save Al&l" { FileSaveAll } + item "&Close\tCtrl+W" { FileClose } + item; + item "E&xit\tCtrl+Q" { ExitEditor } +} + +menu Edit { + item "&Undo\tCtrl+Z" { Undo } + item "&Redo" { Redo } + item; + item "Cu&t\tCtrl+X" { BlockCut } + item "&Copy\tCtrl+C" { BlockCopy } + item "&Paste\tCtrl+V" { BlockPasteStream } +} + +menu Search { + item "&Find...\tCtrl+F" { Find } + item "Find &Next\tCtrl+G" { FindRepeat } + item; + item "Find and &replace...\tCtrl+R" { FindReplace } + item; + item "&Goto line..." { MoveToLine } +} + +menu Help { + item "&About..." { ShowVersion } +} + +menu Main { + submenu "&File", File; + submenu "&Edit", Edit; + submenu "&Search", Search; + submenu "&Help", Help; +} + +menu Local { + item "&Unmark\tEsc" { BlockUnmark } + item "Cu&t\tCtrl+X" { BlockCut } + item "&Copy\tCtrl+C" { BlockCopy } + item "&Paste\tCtrl+V" { BlockPasteStream } + item "Cl&ose\tAlt+Q" { FileClose } +} + +eventmap MODEL { # basic commands, for files, directories, message view, etc. + key [C+O] { FileOpen } + key [C+W] { FileClose } + + key [F10] { MainMenu } + key [S+F10] { LocalMenu } + + key [C+Q] { ExitEditor } + + key [A+G-Left] { FilePrev } + key [A+G-Right] { FileNext } +} + +eventmap PLAIN: MODEL { +# keymap for plaintext mode + MainMenu = 'Main'; # menu for menubar + LocalMenu = 'Local'; # local menu + + key [Esc] { BlockMarkStream; BlockUnmark } + key [C+S] { FileSave } + + key [C+C] { BlockCopy } + key [C+V] { BlockPasteStream } + key [C+X] { BlockCut } + + key [A+BackSp] { Undo } + key [A+S+BackSp] { Redo } + + key [G-Enter] { LineNew } + key [BackSp] { BackSpace } + key [G-Ins] { ToggleInsert } + key [G-Del] { Delete } + key [Tab] { InsertTab } + key [C+BackSp] { KillWordPrev } + + key [C+F] { Find } + key [C+G] { FindRepeat } + + key [G-Left] { MoveLeft } + key [C+G-Left] { MoveWordPrev } + key [G-Right] { MoveRight } + key [C+G-Right] { MoveWordNext } + key [G-Up] { MoveUp } + key [G-Down] { MoveDown } + key [G-Home] { MoveLineStart } + key [C+G-Home] { MovePageStart } + key [G-End] { MoveLineEnd } + key [C+G-End] { MovePageEnd } + key [G-PgUp] { MovePageUp } + key [C+G-PgUp] { MoveFileStart } + key [G-PgDn] { MovePageDown } + key [C+G-PgDn] { MoveFileEnd } + + key [S+G-Left] { BlockExtendBegin; MoveLeft; BlockExtendEnd } + key [S+G-Right] { BlockExtendBegin; MoveRight; BlockExtendEnd } + key [C+G-S+Left] { BlockExtendBegin; MoveWordPrev; BlockExtendEnd } + key [C+G-S+Right] { BlockExtendBegin; MoveWordNext; BlockExtendEnd } + key [G-S+Up] { BlockExtendBegin; MoveUp; BlockExtendEnd } + key [G-S+Down] { BlockExtendBegin; MoveDown; BlockExtendEnd } + key [G-S+Home] { BlockExtendBegin; MoveLineStart; BlockExtendEnd } + key [G-S+End] { BlockExtendBegin; MoveLineEnd; BlockExtendEnd } + key [C+G-S+Home] { BlockExtendBegin; MovePageStart; BlockExtendEnd } + key [C+G-S+End] { BlockExtendBegin; MovePageEnd; BlockExtendEnd } + key [G-S+PgUp] { BlockExtendBegin; MovePageUp; BlockExtendEnd } + key [G-S+PgDn] { BlockExtendBegin; MovePageDown; BlockExtendEnd } + key [C+G-S+PgUp] { BlockExtendBegin; MoveFileStart; BlockExtendEnd } + key [C+G-S+PgDn] { BlockExtendBegin; MoveFileEnd; BlockExtendEnd } + + key [C+G-Ins] { BlockCopy } + key [S+G-Ins] { BlockPasteStream } + key [S+G-Del] { BlockCut } + + key [F7] { BlockBegin } + key [S+F7] { MoveBlockStart } + key [F8] { BlockEnd } + key [S+F8] { MoveBlockEnd } + + key [A+E] { MainMenu 'E' } + key [A+F] { MainMenu 'F' } + key [A+H] { MainMenu 'H' } + key [A+S] { MainMenu 'S' } +} + +colorize PLAIN { + SyntaxParser = 'PLAIN'; + +# color { +# { 'Normal', '-7' }, +# }; +} + +mode PLAIN { + Colorizer = 'PLAIN'; +} + +eventmap LIST { + key [G-Left] { MoveLeft } + key [G-Right] { MoveRight } + key [G-Up] { MoveUp } + key [G-Down] { MoveDown } + key [G-Home] { MoveLineStart } + key [C+G-Home] { MovePageStart } + key [G-End] { MoveLineEnd } + key [C+G-End] { MovePageEnd } + key [G-PgUp] { MovePageUp } + key [C+G-PgUp] { MoveFileStart } + key [G-PgDn] { MovePageDown } + key [C+G-PgDn] { MoveFileEnd } + key [A+G-Up] { ScrollUp } + key [A+G-Down] { ScrollDown } + key [A+G-Left] { ScrollLeft } + key [A+G-Right] { ScrollRight } + + key [Esc] { Cancel } + key [G-Enter] { Activate } +} + +eventmap BUFFERS: LIST { + key [C+F10] { FileClose } + key [F2] { FileSave } +} + +eventmap ROUTINES: LIST { +} + +eventmap MLIST: MODEL { + key [G-Left] { MoveLeft } + key [G-Right] { MoveRight } + key [G-Up] { MoveUp } + key [G-Down] { MoveDown } + key [G-Home] { MoveLineStart } + key [C+G-Home] { MovePageStart } + key [G-End] { MoveLineEnd } + key [C+G-End] { MovePageEnd } + key [G-PgUp] { MovePageUp } + key [C+G-PgUp] { MoveFileStart } + key [G-PgDn] { MovePageDown } + key [C+G-PgDn] { MoveFileEnd } +# key [A+G-Up] { ScrollUp } +# key [A+G-Down] { ScrollDown } +# key [A+G-Left] { ScrollLeft } +# key [A+G-Right] { ScrollRight } + + key [G-Enter] { Activate } +} + +menu Directory { + item "&Next\tF6" { FileNext } + item "&Previous\tShift+F6" { FilePrev } + item; + item "&Close\tAlt+Q" { FileClose } + item; + item "E&xit\tAlt+X" { ExitEditor } +} + +menu Navigate { + item "Go &< level\tCtrl+PgUp" { DirGoUp } + item "Go &> level\tCtrl+PgDn" { DirGoDown } + item "Go to &\\\tCtrl+\\" { DirGoRoot } +# item "&/ Goto Dir\t/" { DirGoto } + item "&\\ Goto Dir\t\\" { DirGoto } + item; + item '&A:\\' { DirGoto 'A:\\' } + item '&B:\\' { DirGoto 'B:\\' } + item '&C:\\' { DirGoto 'C:\\' } + item '&D:\\' { DirGoto 'D:\\' } + item '&E:\\' { DirGoto 'E:\\' } + item '&F:\\' { DirGoto 'F:\\' } + item '&G:\\' { DirGoto 'G:\\' } + item '&H:\\' { DirGoto 'H:\\' } + item '&I:\\' { DirGoto 'I:\\' } +} + +menu DirMain { + submenu "&Directory", Directory; + submenu "&Navigate", Navigate; + submenu "&Tools", Tools; + submenu "&Window", Window; +} + +eventmap DIRECTORY: MLIST { + MainMenu = 'DirMain'; + + key [C+G-PgUp] { DirGoUp } + key [C+G-PgDn] { DirGoDown } + key [C+\\] { DirGoRoot } + key [/] { DirGoto } + key [\\] { DirGoto } + + key [A+D] { MainMenu 'D' } + key [A+N] { MainMenu 'N' } + key [A+W] { MainMenu 'W' } +} + +menu Messages { + item "&Close\tAlt+Q" { FileClose } + item; + item "&Next\tF6" { FileNext } + item "&Previous\tShift+F6" { FilePrev } + item; + item "E&xit\tAlt+X" { ExitEditor } +} + +menu MsgMain { + submenu "&Messages", Messages; + submenu "&Tools", Tools; + submenu "&Window", Window; +} + +eventmap MESSAGES: MLIST { + MainMenu = "MsgMain"; + + key [A+M] { MainMenu 'M' } + key [A+T] { MainMenu 'T' } + key [A+W] { MainMenu 'W' } +} diff --git a/src/dialog.h b/src/dialog.h new file mode 100644 index 0000000..b66d06f --- /dev/null +++ b/src/dialog.h @@ -0,0 +1,23 @@ +/* dialog.h + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#ifndef __DIALOG_H__ +#define __DIALOG_H__ + +#define askYes 0 +#define askNo 1 +#define askCancel 2 +#define askOK 3 + +int AskString(char *Prompt, char *String, int MaxLen); +int AskYesNo(char *Prompt); +int AskYesNoCancel(char *Prompt); +int AskOKCancel(char *Prompt); + +#endif diff --git a/src/e_block.cpp b/src/e_block.cpp new file mode 100644 index 0000000..385e779 --- /dev/null +++ b/src/e_block.cpp @@ -0,0 +1,1069 @@ +/* e_block.cpp + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#include "fte.h" + +/////////////////////////////////////////////////////////////////////////////// +// Block Commands // +/////////////////////////////////////////////////////////////////////////////// + +int EBuffer::SetBB(EPoint M) { + EPoint OldBB = BB; + int MinL, MaxL; + + if (BB.Row == M.Row && BB.Col == M.Col) return 1; +#ifdef CONFIG_UNDOREDO + if (PushBlockData() == 0) return 0; +#endif + BB = M; + if (OldBB.Row == -1) OldBB = BE; + if ((OldBB.Col != BB.Col) && (BlockMode == bmColumn)) BlockRedraw(); + MinL = Min(OldBB.Row, BB.Row); + MaxL = Max(OldBB.Row, BB.Row); + if (MinL != -1) + if (MinL <= MaxL) Draw(MinL, MaxL); + return 1; +} + +int EBuffer::SetBE(EPoint M) { + EPoint OldBE = BE; + int MinL, MaxL; + + if (BE.Row == M.Row && BE.Col == M.Col) return 1; +#ifdef CONFIG_UNDOREDO + if (PushBlockData() == 0) return 0; +#endif + BE = M; + if (OldBE.Row == -1) OldBE = BB; + if ((OldBE.Col != BE.Col) && (BlockMode == bmColumn)) BlockRedraw(); + MinL = Min(OldBE.Row, BE.Row); + MaxL = Max(OldBE.Row, BE.Row); + if (MinL != -1) + if (MinL <= MaxL) Draw(MinL, MaxL); + return 1; +} + +int EBuffer::CheckBlock() { + if (BB.Row == -1 && BE.Row == 1) { + BB.Col = -1; + BE.Col = -1; + return 0; + } + if (BB.Row == -1 || BE.Row == -1) return 0; + if (BB.Row >= RCount) BB.Row = RCount - 1; + if (BE.Row >= RCount) BE.Row = RCount - 1; + switch(BlockMode) { + case bmLine: + BB.Col = 0; + BE.Col = 0; + if (BB.Row >= BE.Row) return 0; + break; + case bmColumn: + if (BB.Col >= BE.Col) return 0; + if (BB.Row >= BE.Row) return 0; + break; + case bmStream: + if (BB.Row > BE.Row) return 0; + if (BB.Row == BE.Row && BB.Col >= BE.Col) return 0; + break; + } + return 1; +} + +int EBuffer::BlockRedraw() { + if (BB.Row == -1 || BE.Row == -1) return 0; + Draw(BB.Row, BE.Row); + return 1; +} + + +int EBuffer::BlockBegin() { + EPoint X; + + X.Row = VToR(CP.Row); + X.Col = CP.Col; + CheckBlock(); + SetBB(X); + return 1; +} + +int EBuffer::BlockEnd() { + EPoint X; + + X.Row = VToR(CP.Row); + X.Col = CP.Col; + CheckBlock(); + SetBE(X); + return 1; +} + +int EBuffer::BlockUnmark() { + EPoint Null(-1,-1); + + SetBB(BE); + SetBE(Null); + SetBB(Null); + AutoExtend = 0; + return 1; +} + +int EBuffer::BlockCut(int Append) { + if (BlockCopy(Append) && BlockKill()) return 1; + return 0; +} + +int EBuffer::BlockCopy(int Append) { + EPoint B, E; + int L; + int SL, OldCount; + + AutoExtend = 0; + if (CheckBlock() == 0) return 0; + if (RCount == 0) return 0; + if (SSBuffer == 0) return 0; + if (Append) { + if (SystemClipboard) + GetPMClip(); + } else + SSBuffer->Clear(); + SSBuffer->BlockMode = BlockMode; + BFI(SSBuffer, BFI_TabSize) = BFI(this, BFI_TabSize); + BFI(SSBuffer, BFI_ExpandTabs) = BFI(this, BFI_ExpandTabs); + BFI(SSBuffer, BFI_Undo) = 0; + B = BB; + E = BE; + OldCount = SL = SSBuffer->RCount; + switch (BlockMode) { + case bmLine: + for (L = B.Row; L < E.Row; L++) { + if (SSBuffer->InsLine(SL, 0) == 0) return 0; + if (SSBuffer->InsLineText(SL, 0, -1, 0, RLine(L)) == 0) return 0; + SL++; + } + break; + + case bmColumn: + for (L = B.Row; L < E.Row; L++) { + if (SSBuffer->InsLine(SL, 0) == 0) return 0; + if (SSBuffer->InsLineText(SL, 0, E.Col - B.Col, B.Col, RLine(L)) == 0) return 0; + if (SSBuffer->PadLine(SL, E.Col - B.Col) == 0) return 0; + SL++; + } + break; + + case bmStream: + if (B.Row == E.Row) { + if (SSBuffer->InsLine(SL, 0) == 0) return 0; + if (SSBuffer->InsLineText(SL, 0, E.Col - B.Col, B.Col, RLine(B.Row)) == 0) return 0; + } else { + if (SSBuffer->InsLine(SL, 0) == 0) return 0; + if (SSBuffer->InsLineText(SL, 0, -1, B.Col, RLine(B.Row)) == 0) return 0; + SL++; + for (L = B.Row + 1; L < E.Row; L++) { + if (SSBuffer->InsLine(SL, 0) == 0) return 0; + if (SSBuffer->InsLineText(SL, 0, -1, 0, RLine(L)) == 0) return 0; + SL++; + } + if (SSBuffer->InsLine(SL, 0) == 0) return 0; + if (SSBuffer->InsLineText(SL, 0, E.Col, 0, RLine(E.Row)) == 0) return 0; + } + if (Append && OldCount > 0) + if (SSBuffer->JoinLine(OldCount - 1, 0) == 0) + return 0; + break; + } + if (SystemClipboard) + PutPMClip(); + return 1; +} + +int EBuffer::BlockPasteStream() { + BlockMode = bmStream; + return BlockPaste(); +} + +int EBuffer::BlockPasteLine() { + BlockMode = bmLine; + return BlockPaste(); +} + +int EBuffer::BlockPasteColumn() { + BlockMode = bmColumn; + return BlockPaste(); +} + +int EBuffer::BlockPaste() { + EPoint B, E; + int L, BL; + + if (SystemClipboard) + GetPMClip(); + + if (SSBuffer == 0) return 0; + if (SSBuffer->RCount == 0) return 0; + AutoExtend = 0; + BFI(SSBuffer, BFI_TabSize) = BFI(this, BFI_TabSize); + BFI(SSBuffer, BFI_ExpandTabs) = BFI(this, BFI_ExpandTabs); + BFI(SSBuffer, BFI_Undo) = 0; + BlockUnmark(); + B.Row = VToR(CP.Row); + B.Col = CP.Col; + BL = B.Row; + switch(BlockMode) { + case bmLine: + B.Col = 0; + for (L = 0; L < SSBuffer->RCount; L++) { + if (InsLine(BL, 0) == 0) return 0; + if (InsLineText(BL, 0, SSBuffer->LineLen(L), 0, SSBuffer->RLine(L)) == 0) return 0; + BL++; + } + E.Row = BL; + E.Col = 0; + SetBB(B); + SetBE(E); + break; + + case bmColumn: + for (L = 0; L < SSBuffer->RCount; L++) { + if (AssertLine(BL) == 0) return 0; + if (InsLineText(BL, B.Col, SSBuffer->LineLen(L), 0, SSBuffer->RLine(L)) == 0) return 0; + if (TrimLine(BL) == 0) return 0; + BL++; + } + if (AssertLine(BL) == 0) return 0; + E.Row = BL; + E.Col = B.Col + SSBuffer->LineLen(0); + SetBB(B); + SetBE(E); + break; + + case bmStream: + if (SSBuffer->RCount > 1) + if (SplitLine(B.Row, B.Col) == 0) return 0; + if (InsLineText(B.Row, B.Col, SSBuffer->LineLen(0), 0, SSBuffer->RLine(0)) == 0) return 0; + E = B; + E.Col += SSBuffer->LineLen(0); + BL++; + if (SSBuffer->RCount > 1) { + for (L = 1; L < SSBuffer->RCount - 1; L++) { + if (InsLine(BL, 0) == 0) return 0; + if (InsLineText(BL, 0, SSBuffer->LineLen(L), 0, SSBuffer->RLine(L)) == 0) return 0; + BL++; + } + L = SSBuffer->RCount - 1; + if (InsLineText(BL, 0, SSBuffer->LineLen(L), 0, SSBuffer->RLine(L)) == 0) return 0; + E.Col = SSBuffer->LineLen(L); + E.Row = BL; + } + SetBB(B); + SetBE(E); + break; + } + return 1; +} + +int EBuffer::BlockKill() { + EPoint B, E; + int L; + int Y = -1; + + AutoExtend = 0; + if (CheckBlock() == 0) return 0; + if (RCount <= 0) return 0; + B = BB; + E = BE; + Draw(B.Row, -1); + // if (MoveToPos(B.Col, B.Row) == 0) return 0; + +#ifdef CONFIG_UNDOREDO + if (BFI(this, BFI_Undo) == 1) { + if (PushULong(CP.Col) == 0) return 0; + if (PushULong(CP.Row) == 0) return 0; + if (PushUChar(ucPosition) == 0) return 0; + } +#endif + + switch (BlockMode) { + case bmLine: + Y = VToR(CP.Row); + if (Y >= B.Row) { + if (Y >= E.Row) { + if (SetPosR(CP.Col, Y - (E.Row - B.Row)) == 0) return 0; + } else { + if (SetPosR(CP.Col, B.Row) == 0) return 0; + } + } + for (L = B.Row; L < E.Row; L++) + if (DelLine(B.Row) == 0) return 0; + break; + + case bmColumn: + Y = VToR(CP.Row); + if (Y >= B.Row && Y < E.Row) { + if (CP.Col >= B.Col) { + if (CP.Col >= E.Col) { + if (SetPos(CP.Col - (E.Col - B.Col), CP.Row) == 0) return 0; + } else { + if (SetPos(B.Col, CP.Row) == 0) return 0; + } + } + } + for (L = B.Row; L < E.Row; L++) + if (DelText(L, B.Col, E.Col - B.Col) == 0) return 0; + break; + + case bmStream: + Y = VToR(CP.Row); + + if (B.Row == E.Row) { + if (Y == B.Row) { + if (CP.Col >= B.Col) { + if (CP.Col >= E.Col) { + if (SetPos(CP.Col - (E.Col - B.Col), CP.Row) == 0) return 0; + } else { + if (SetPos(B.Col, CP.Row) == 0) return 0; + } + } + } + if (DelText(B.Row, B.Col, E.Col - B.Col) == 0) return 0; + } else { + if (Y >= B.Row) { + if (Y > E.Row || (Y == E.Row && E.Col == 0)) { + if (SetPosR(CP.Col, Y - (E.Row - B.Row)) == 0) return 0; + } else if (Y == E.Row) { + if (CP.Col >= E.Col) { + if (SetPosR(CP.Col - E.Col + B.Col, B.Row) == 0) return 0; + } else { + if (SetPosR(B.Col, B.Row) == 0) return 0; + } + } else { + if (SetPosR(B.Col, B.Row) == 0) return 0; + } + } + if (DelText(E.Row, 0, E.Col) == 0) return 0; + for (L = B.Row + 1; L < E.Row; L++) + if (DelLine(B.Row + 1) == 0) return 0; + if (DelText(B.Row, B.Col, -1) == 0) return 0; + if (JoinLine(B.Row, B.Col) == 0) return 0; + } + break; + } + return BlockUnmark(); +} + +int EBuffer::ClipClear() { + if (SSBuffer == 0) + return 0; + SSBuffer->Clear(); + if (SystemClipboard) + PutPMClip(); + return 1; +} + +int EBuffer::BlockIndent() { + EPoint B, E; + int L; + + AutoExtend = 0; + if (CheckBlock() == 0) return 0; + if (RCount <= 0) return 0; + B = BB; + E = BE; + Draw(B.Row, E.Row); + if (SetPosR(B.Col, B.Row) == 0) return 0; + for (L = B.Row; L <= E.Row; L++) { + switch (BlockMode) { + case bmStream: + case bmLine: + if (L < E.Row || E.Col != 0) { + int I = LineIndented(L) + 1; + IndentLine(L, I); + } + break; + case bmColumn: + if (L < E.Row) { + if (InsText(L, B.Col, 1, 0) == 0) return 0; + if (DelText(L, E.Col, 1) == 0) return 0; + } + break; + } + } + if (SetPosR(B.Col, B.Row) == 0) return 0; + return 1; +} + +int EBuffer::BlockUnindent() { + EPoint B, E; + int L; + + AutoExtend = 0; + if (CheckBlock() == 0) return 0; + if (RCount <= 0) return 0; + B = BB; + E = BE; + Draw(B.Row, E.Row); + if (SetPosR(B.Col, B.Row) == 0) return 0; + for (L = B.Row; L <= E.Row; L++) { + switch (BlockMode) { + case bmStream: + case bmLine: + if (L < E.Row || E.Col != 0) { + int I = LineIndented(L) - 1; + if (I >= 0) + IndentLine(L, I); + } + break; + case bmColumn: + if (L < E.Row) { + if (InsText(L, E.Col, 1, 0) == 0) return 0; + if (DelText(L, B.Col, 1) == 0) return 0; + } + break; + } + } + if (SetPosR(B.Col, B.Row) == 0) return 0; + return 1; +} + +int EBuffer::BlockClear() { + return 0; +} + +int EBuffer::BlockMarkStream() { + if (BlockMode != bmStream) BlockUnmark(); + BlockMode= bmStream; + if (AutoExtend) AutoExtend = 0; + else { + BlockUnmark(); + AutoExtend = 1; + } + return 1; +} + +int EBuffer::BlockMarkLine() { + if (BlockMode != bmLine) BlockUnmark(); + BlockMode= bmLine; + if (AutoExtend) AutoExtend = 0; + else { + BlockUnmark(); + AutoExtend = 1; + } + return 1; +} + +int EBuffer::BlockMarkColumn() { + if (BlockMode != bmColumn) BlockUnmark(); + BlockMode= bmColumn; + if (AutoExtend) AutoExtend = 0; + else { + BlockUnmark(); + AutoExtend = 1; + } + return 1; +} + +int EBuffer::BlockExtendBegin() { + CheckBlock(); + ExtendGrab = 0; + AutoExtend = 0; + int Y = VToR(CP.Row); + + switch (BlockMode) { + case bmStream: + if ((Y == BB.Row) && (CP.Col == BB.Col)) ExtendGrab |= 1; + if ((Y == BE.Row) && (CP.Col == BE.Col)) ExtendGrab |= 2; + break; + case bmLine: + if (Y == BB.Row) ExtendGrab |= 1; + if (Y == BE.Row) ExtendGrab |= 2; + break; + case bmColumn: + if (Y == BB.Row) ExtendGrab |= 1; + if (Y == BE.Row) ExtendGrab |= 2; + if (CP.Col == BB.Col) ExtendGrab |= 4; + if (CP.Col == BE.Col) ExtendGrab |= 8; + break; + } + + if (ExtendGrab == 0) { + BlockBegin(); + BlockEnd(); + if (BlockMode == bmColumn) + ExtendGrab = 1 | 2 | 4 | 8; + else + ExtendGrab = 1 | 2; + } + return 1; +} + +int EBuffer::BlockExtendEnd() { + EPoint T, B, E; + + CheckBlock(); + B = BB; + E = BE; + switch (BlockMode) { + case bmLine: + if (ExtendGrab & 1) { B.Row = VToR(CP.Row); B.Col = 0; } + else if (ExtendGrab & 2) { E.Row = VToR(CP.Row); E.Col = 0; } + if (B.Row > E.Row) { + T = B; + B = E; + E = T; + } + break; + case bmStream: + if (ExtendGrab & 1) { B.Col = CP.Col; B.Row = VToR(CP.Row); } + else if (ExtendGrab & 2) { E.Col = CP.Col; E.Row = VToR(CP.Row); } + if ((B.Row > E.Row) || + ((B.Row == E.Row) && (B.Col > E.Col))) { + T = B; + B = E; + E = T; + } + break; + case bmColumn: + if (ExtendGrab & 1) B.Row = VToR(CP.Row); + else if (ExtendGrab & 2) E.Row = VToR(CP.Row); + if (ExtendGrab & 4) B.Col = CP.Col; + else if (ExtendGrab & 8) E.Col = CP.Col; + if (B.Row > E.Row) { + int T; + + T = B.Row; + B.Row = E.Row; + E.Row = T; + } + if (B.Col > E.Col) { + int T; + + T = B.Col; + B.Col = E.Col; + E.Col = T; + } + break; + } + SetBB(B); + SetBE(E); + ExtendGrab = 0; + AutoExtend = 0; + return 1; +} + +int EBuffer::BlockIsMarked() { + if ((BB.Row != -1) && (BE.Row != -1) && (BB.Col != -1) && (BE.Col != -1)) return 1; + return 0; +} + +int EBuffer::BlockReIndent() { + EPoint P = CP; + EPoint B, E; + + AutoExtend = 0; + if (CheckBlock() == 0) return 0; + if (RCount <= 0) return 0; + B = BB; + E = BE; + Draw(B.Row, E.Row); + for (int i = B.Row; i < E.Row; i++) { + if (SetPosR(0, i) == 0) return 0; + if (LineIndent() == 0) return 0; + } + return SetPos(P.Col, P.Row); +} + +int EBuffer::BlockSelectWord() { + int Y = VToR(CP.Row); + PELine L = RLine(Y); + int P; + int C; + + if (BlockUnmark() == 0) return 0; + BlockMode = bmStream; + + P = CharOffset(L, CP.Col); + + if (P >= L->Count) return 0; + C = ChClassK(L->Chars[P]); + + while ((P > 0) && (C == ChClassK(L->Chars[P - 1]))) P--; + if (SetBB(EPoint(Y, ScreenPos(L, P))) == 0) return 0; + while ((P < L->Count) && (C == ChClassK(L->Chars[P]))) P++; + if (SetBE(EPoint(Y, ScreenPos(L, P))) == 0) return 0; + return 1; +} + +int EBuffer::BlockSelectLine() { + int Y = VToR(CP.Row); + if (BlockUnmark() == 0) return 0; + BlockMode = bmStream; + + if (SetBB(EPoint(Y, 0)) == 0) return 0; + if (Y == RCount - 1) { + if (SetBE(EPoint(Y, LineLen(Y))) == 0) return 0; + } else { + if (SetBE(EPoint(Y + 1, 0)) == 0) return 0; + } + return 1; +} + +int EBuffer::BlockSelectPara() { + return 1; +} + +int EBuffer::BlockWriteTo(char *AFileName, int Append) { + //int error = 0; + EPoint B, E; + int L; + PELine LL; + int A, Z; + FILE *fp; + int bc = 0, lc = 0, oldc = 0; + + AutoExtend = 0; + if (CheckBlock() == 0) return 0; + if (RCount == 0) return 0; + B = BB; + E = BE; + Msg(S_INFO, "Writing %s...", AFileName); + fp = fopen(AFileName, Append ? "ab" : "wb"); + if (fp == NULL) goto error; + setvbuf(fp, FileBuffer, _IOFBF, sizeof(FileBuffer)); + for (L = B.Row; L <= E.Row; L++) { + A = -1; + Z = -1; + LL = RLine(L); + switch (BlockMode) { + case bmLine: + if (L < E.Row) { + A = 0; + Z = LL->Count; + } + break; + case bmColumn: + if (L < E.Row) { + A = CharOffset(LL, B.Col); + Z = CharOffset(LL, E.Col); + } + break; + case bmStream: + if (B.Row == E.Row) { + A = CharOffset(LL, B.Col); + Z = CharOffset(LL, E.Col); + } else if (L == B.Row) { + A = CharOffset(LL, B.Col); + Z = LL->Count; + } else if (L < E.Row) { + A = 0; + Z = LL->Count; + } else if (L == E.Row) { + A = 0; + Z = CharOffset(LL, E.Col); + } + break; + } + if (A != -1 && Z != -1) { + if (A < LL->Count) { + if (Z > LL->Count) + Z = LL->Count; + if (Z > A) { + if ((int)fwrite(LL->Chars + A, 1, Z - A, fp) != Z - A) { + goto error; + } else + bc += Z - A; + } + } + if (BFI(this, BFI_AddCR) == 1) + if (fputc(13, fp) < 0) goto error; + else + bc++; + if (BFI(this, BFI_AddLF) == 1) + if (fputc(10, fp) < 0) + goto error; + else { + bc++; + lc++; + } + if (bc > 65536 + oldc) { + Msg(S_INFO, "Writing %s, %d lines, %d bytes.", AFileName, lc, bc); + oldc = bc; + } + } + } + fclose(fp); + Msg(S_INFO, "Wrote %s, %d lines, %d bytes.", AFileName, lc, bc); + return 1; +error: + if(fp != NULL) + { + fclose(fp); + unlink(AFileName); + } + View->MView->Win->Choice(GPC_ERROR, "Error", 1, "O&K", "Failed to write block to %s", AFileName); + return 0; +} + +int EBuffer::BlockReadFrom(char *AFileName, int blockMode) { + EBuffer *B; + int savesys; + int rc; + + if (FileExists(AFileName) == 0) { + View->MView->Win->Choice(GPC_ERROR, "Error", 1, "O&K", "File not found: %s", AFileName); + return 0; + } + + B = new EBuffer(0, (EModel **)&SSBuffer, AFileName); + if (B == 0) return 0; + B->SetFileName(AFileName, 0); + if (B->Load() == 0) { + delete B; + return 0; + } + + savesys = SystemClipboard; + SystemClipboard = 0; + + switch (blockMode) { + case bmColumn: rc = BlockPasteColumn(); break; + case bmLine: rc = BlockPasteLine(); break; + default: + case bmStream: rc = BlockPasteStream(); break; + } + + SystemClipboard = savesys; + + if (rc == 0) + return 0; + delete B; + return 1; +} + +static EBuffer *SortBuffer; +static int SortReverse; +static int *SortRows = 0; +static int SortMinRow; +static int SortMaxRow; +static int SortMinCol; +static int SortMaxCol; + +static int _LNK_CONV SortProc(const void *A, const void *B) { + int *AA = (int *)A; + int *BB = (int *)B; + ELine *LA = SortBuffer->RLine(*AA); + ELine *LB = SortBuffer->RLine(*BB); + int rc; + + if (SortMinCol == -1) { + int lA = LA->Count; + int lB = LB->Count; + + if (BFI(SortBuffer, BFI_MatchCase) == 1) + rc = memcmp(LA->Chars, LB->Chars, (lA < lB) ? lA : lB); + else + rc = memicmp(LA->Chars, LB->Chars, (lA < lB) ? lA : lB); + if (rc == 0) { + if (lA > lB) + rc = 1; + else + rc = -1; + } + } else { + int lA = LA->Count; + int lB = LB->Count; + int PA = SortBuffer->CharOffset(LA, SortMinCol); + int PB = SortBuffer->CharOffset(LB, SortMinCol); + + lA -= PA; + lB -= PB; + if (lA < 0 && lB < 0) + rc = 0; + else if (lA < 0 && lB > 0) + rc = -1; + else if (lA > 0 && lB < 0) + rc = 1; + else { + if (SortMaxCol != -1) { + if (lA > SortMaxCol - SortMinCol) + lA = SortMaxCol - SortMinCol; + if (lB > SortMaxCol - SortMinCol) + lB = SortMaxCol - SortMinCol; + } + if (BFI(SortBuffer, BFI_MatchCase) == 1) + rc = memcmp(LA->Chars+ PA, LB->Chars + PB, (lA < lB) ? lA : lB); + else + rc = memicmp(LA->Chars + PA, LB->Chars + PB, (lA < lB) ? lA : lB); + if (rc == 0) { + if (lA > lB) + rc = 1; + else + rc = -1; + } + } + } + + if (SortReverse) + return -rc; + return rc; +} + +int EBuffer::BlockSort(int Reverse) { + int rq; + ELine *oldL; + + if (CheckBlock() == 0) return 0; + if (RCount == 0) return 0; + + SortMinRow = BB.Row; + SortMaxRow = BE.Row; + if (BlockMode != bmStream || BE.Col == 0) + SortMaxRow--; + + if (SortMinRow >= SortMaxRow) + return 1; + + SortBuffer = this; + SortReverse = Reverse; + switch (BlockMode) { + case bmLine: + case bmStream: + SortMinCol = -1; + SortMaxCol = -1; + break; + + case bmColumn: + SortMinCol = BB.Col; + SortMaxCol = BE.Col; + break; + } + + SortRows = (int *)malloc((SortMaxRow - SortMinRow + 1) * sizeof(int)); + if (SortRows == 0) { + free(SortRows); + return 0; + } + for (rq = 0; rq <= SortMaxRow - SortMinRow; rq++) + SortRows[rq] = rq + SortMinRow; + + qsort(SortRows, SortMaxRow - SortMinRow + 1, sizeof(int), SortProc); + + // now change the order of lines according to new order in Rows array. + + for (rq = 0; rq <= SortMaxRow - SortMinRow; rq++) { + oldL = RLine(SortRows[rq]); + if (InsLine(1 + rq + SortMaxRow, 0) == 0) + return 0; + if (InsChars(1 + rq + SortMaxRow, 0, oldL->Count, oldL->Chars) == 0) + return 0; + } + + for (rq = 0; rq <= SortMaxRow - SortMinRow; rq++) + if (DelLine(SortMinRow) == 0) + return 0; + + free(SortRows); + return 1; +} + +int EBuffer::BlockUnTab() { + EPoint B, E; + ELine *L; + int O, C; + + AutoExtend = 0; + if (CheckBlock() == 0) return 0; + if (RCount <= 0) return 0; + B = BB; + E = BE; + Draw(B.Row, E.Row); + for (int i = B.Row; i < E.Row; i++) { + L = RLine(i); + O = 0; + C = 0; + while (O < L->Count) { + if (L->Chars[O] == '\t') { + C = NextTab(C, BFI(this, BFI_TabSize)); + + if (DelChars(i, O, 1) != 1) + return 0; + if (InsChars(i, O, C - O, 0) != 1) + return 0; + O = C; + } else { + O++; + C++; + } + } + } + return 1; +} + +int EBuffer::BlockEnTab() { + EPoint B, E; + ELine *L; + int O, C, O1, C1; + char tab = '\t'; + + AutoExtend = 0; + if (CheckBlock() == 0) return 0; + if (RCount <= 0) return 0; + B = BB; + E = BE; + Draw(B.Row, E.Row); + for (int i = B.Row; i < E.Row; i++) { + L = RLine(i); + O = C = 0; + O1 = C1 = 0; + while (O < L->Count) { + if (L->Chars[O] == '\t') { // see if there are spaces to remove + int C2 = NextTab(C, BFI(this, BFI_TabSize)); + int N = BFI(this, BFI_TabSize) - (C2 - C); + if (O - O1 < N) + N = O - O1; + if (N > 0) { + if (DelChars(i, O - N, N) != 1) + return 0; + O -= N; + C = C2; + O++; + C1 = C; + O1 = O; + } else { + O++; + C = C2; + O1 = O; + C1 = C; + } + } else if (L->Chars[O] != ' ') { // nope, cannot put tab here + O++; + C++; + C1 = C; + O1 = O; + } else if (((C % BFI(this, BFI_TabSize)) == (BFI(this, BFI_TabSize) - 1)) && + (C - C1 > 0)) + { // reached a tab and can put one + int N = BFI(this, BFI_TabSize); + if (O - O1 + 1 < N) { + N = O - O1 + 1; + } else if (O - O1 + 1 > N) { + O1 = O - N + 1; + } + if (DelChars(i, O1, N) != 1) + return 0; + if (InsChars(i, O1, 1, &tab) != 1) + return 0; + O1++; + O = O1; + C++; + C1 = C; + } else { + O++; + C++; + } + } + } + return 1; +} + +// FindFunction -- search for line matching 'RoutineRegexp' +// starting from current line + 'delta'. 'way' should be +1 or -1. +int EBuffer::FindFunction(int delta, int way) { + RxNode *regx; + int line; + PELine L; + RxMatchRes res; + + if (BFS(this, BFS_RoutineRegexp) == 0) { + View->MView->Win->Choice(GPC_ERROR, "Error", 1, + "O&K", "No routine regexp."); + return -1; + } + regx = RxCompile(BFS(this, BFS_RoutineRegexp)); + if (regx == 0) { + View->MView->Win->Choice(GPC_ERROR, "Error", 1, + "O&K", "Failed to compile regexp '%s'", + BFS(this, BFS_RoutineRegexp)); + return -1; + } + + //** Scan backwards from the current cursor position, + Msg(S_BUSY, "Matching %s", BFS(this, BFS_RoutineRegexp)); + line = VToR(CP.Row) + delta; + while (line >= 0 && line < RCount) { + L = RLine(line); + if (RxExec(regx, L->Chars, L->Count, L->Chars, &res) == 1) + break; + line += way; + } + if (line < 0) + line = 0; + if (line >= RCount) + line = RCount - 1; + RxFree(regx); + return line; +} + +// Selects the current function. +int EBuffer::BlockMarkFunction() { + int by, ey; + + if (BlockUnmark() == 0) + return 0; + + if ((by = FindFunction( 0, -1)) == -1) + return 0; + if ((ey = FindFunction(+1, +1)) == -1) + return 0; + + //** Start and end are known. Set the block; + BlockMode = bmStream; + if (SetBB(EPoint(by, 0)) == 0) + return 0; + if (SetBE(EPoint(ey, 0)) == 0) + return 0; + + return 1; +} + +int EBuffer::IndentFunction() { + EPoint P = CP; + int by, ey; + + if ((by = FindFunction( 0, -1)) == -1) + return 0; + if ((ey = FindFunction(+1, +1)) == -1) + return 0; + + //Draw(by, ey); ? + for (int i = by; i < ey; i++) { + if (SetPosR(0, i) == 0) + return 0; + if (LineIndent() == 0) + return 0; + } + return SetPos(P.Col, P.Row); +} + +int EBuffer::MoveFunctionPrev() { + int line = FindFunction(-1, -1); + + if (line == -1) + return 0; + + return CenterPosR(0, line); +} + +int EBuffer::MoveFunctionNext() { + int line = FindFunction(+1, +1); + + if (line == -1) + return 0; + + return CenterPosR(0, line); +} diff --git a/src/e_buffer.cpp b/src/e_buffer.cpp new file mode 100644 index 0000000..457874b --- /dev/null +++ b/src/e_buffer.cpp @@ -0,0 +1,983 @@ +/* e_buffer.cpp + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#include "fte.h" + +EBuffer *SSBuffer = 0; // scrap buffer (clipboard) + +/////////////////////////////////////////////////////////////////////////////// + +EBuffer::EBuffer(int createFlags, EModel **ARoot, const char * /*AName*/) + :EModel(createFlags, ARoot), TP(0,0), CP(0,0), BB(-1,-1), BE(-1,-1), + PrevPos(-1, -1), SavedPos(-1, -1), Match(-1, -1) +{ + Modified = 0; + Loaded = 0; + Loading = 0; + + FileName = 0; + LL = 0; + VV = 0; + FF = 0; + RGap = RCount = RAllocated = 0; + VGap = VCount = VAllocated = 0; + FCount = 0; + Modified = 0; + BlockMode = bmStream; + ExtendGrab = 0; + AutoExtend = 0; + MatchLen = MatchCount = 0; +#ifdef CONFIG_UNDOREDO + US.Num = 0; + US.Data = 0; + US.Top = 0; + US.UndoPtr = 0; + US.NextCmd = 1; + US.Record = 1; + US.Undo = 0; +#endif +#ifdef CONFIG_BOOKMARKS + BMCount = 0; + BMarks = 0; +#endif +#ifdef CONFIG_OBJ_ROUTINE + rlst.Count = 0; + rlst.Lines = 0; + Routines = 0; +#endif +#ifdef CONFIG_WORD_HILIT + WordList = 0; + WordCount = 0; +#endif + //Name = strdup(AName); + Allocate(0); + AllocVis(0); + Mode = GetModeForName(""); + Flags = (Mode->Flags); + BFI(this, BFI_Undo) = 0; + BFI(this, BFI_ReadOnly) = 0; + Modified = 0; + MinRedraw = -1; + MaxRedraw = -1; + RedrawToEos = 0; +#ifdef CONFIG_SYNTAX_HILIT + StartHilit = 0; + EndHilit = -1; + HilitProc = 0; + if (Mode && Mode->fColorize) + HilitProc = GetHilitProc(Mode->fColorize->SyntaxParser); +#endif + InsertLine(CP,0,0); /* there should always be at least one line in the edit buffer */ + Flags = (Mode->Flags); + Modified = 0; +} + +EBuffer::~EBuffer() { +#ifdef CONFIG_HISTORY + if (FileName != 0 && Loaded) + UpdateFPos(FileName, VToR(CP.Row), CP.Col); +#endif + if (FileName && Loaded) + markIndex.storeForBuffer(this); + + Clear(); + if (LL) + free(LL); + //free(Name); + if (FileName) + free(FileName); +#ifdef CONFIG_BOOKMARKS + if (BMCount != 0) { + for (int i = 0; i < BMCount; i++) + free(BMarks[i].Name); + free(BMarks); + BMarks = 0; + BMCount = 0; + } +#endif +#ifdef CONFIG_OBJ_ROUTINE + if (rlst.Lines) { + free(rlst.Lines); + rlst.Lines = 0; + } +#endif +} + +void EBuffer::DeleteRelated() { +#ifdef CONFIG_OBJ_ROUTINE + if (Routines) { + ::ActiveView->DeleteModel(Routines); + Routines = 0; + } +#endif +} + +int EBuffer::Clear() { + Modified = 1; +#ifdef CONFIG_SYNTAX_HILIT + EndHilit = -1; + StartHilit = 0; + + while (WordCount--) + { + free(WordList[WordCount]); + } + free(WordList); + + WordCount = 0; + WordList = 0; +#endif +#ifdef CONFIG_OBJ_ROUTINE + rlst.Count = 0; + if (rlst.Lines) { + free(rlst.Lines); + rlst.Lines = 0; + } +#endif + if (LL) + { + for (int i = 0; i < RCount; i++) + delete LL[GapLine(i, RGap, RCount, RAllocated)]; + free(LL); + LL = 0; + } + RCount = RAllocated = RGap = 0; + VCount = VAllocated = VGap = 0; + if (VV) + { + free(VV); + VV = 0; + } +#ifdef CONFIG_UNDOREDO + FreeUndo(); +#endif + if (FCount != 0) { + free(FF); + FCount = 0; + FF = 0; + } + return 0; +} + +#ifdef CONFIG_UNDOREDO +int EBuffer::FreeUndo() { + for (int j = 0; j < US.Num; j++) + free(US.Data[j]); + free(US.Top); + free(US.Data); + US.Num = 0; + US.Data = 0; + US.Top = 0; + US.Undo = 0; + US.Record = 1; + US.UndoPtr = 0; + return 1; +} +#endif + +int EBuffer::Modify() { + if (BFI(this, BFI_ReadOnly)) { + Msg(S_ERROR, "File is read-only."); + return 0; + } + if (Modified == 0) { + struct stat StatBuf; + + if ((FileName != 0) && FileOk && (stat(FileName, &StatBuf) == 0)) { + if (FileStatus.st_size != StatBuf.st_size || + FileStatus.st_mtime != StatBuf.st_mtime) + { + View->MView->Win->Choice(GPC_ERROR, "Warning! Press Esc!", + 0, + "File %-.55s changed on disk!", + FileName); + switch (View->MView->Win->Choice(0, "File Changed on Disk", + 2, + "&Modify", + "&Cancel", + "%s", FileName)) + { + case 0: + break; + case 1: + case -1: + default: + return 0; + } + } + } +#ifdef CONFIG_UNDOREDO + if (BFI(this, BFI_Undo)) + if (PushUChar(ucModified) == 0) return 0; +#endif + } + Modified++; + if (Modified == 0) Modified++; + return 1; +} + +int EBuffer::LoadRegion(EPoint * /*A*/, int /*FH*/, int /*StripChar*/, int /*LineChar*/) { + return 0; +} + +int EBuffer::InsertLine(EPoint Pos, int ACount, char *AChars) { + if (InsLine(Pos.Row, 0) == 0) return 0; + if (InsText(Pos.Row, Pos.Col, ACount, AChars) == 0) return 0; + return 1; +} + + +int EBuffer::UpdateMark(EPoint &M, int Type, int Row, int Col, int Rows, int Cols) { + switch (Type) { + case umInsert: /* text inserted */ + switch (BlockMode) { + case bmLine: + case bmColumn: + if (M.Row >= Row) + M.Row += Rows; + break; + case bmStream: + if (Cols) { + if (M.Row == Row) + if (M.Col >= Col) + M.Col += Cols; + } + if (Rows) { + if (M.Row >= Row) + M.Row += Rows; + } + break; + } + break; + case umDelete: + switch (BlockMode) { + case bmLine: + case bmColumn: + if (M.Row >= Row) + if (InRange(Row, M.Row, Row + Rows)) + M.Row = Row; + else + M.Row -= Rows; + break; + case bmStream: + if (Cols) { + if (M.Row == Row) + if (M.Col >= Col) + if (M.Col < Col + Cols) + M.Col = Col; + else + M.Col -= Cols; + } + if (Rows) { + if (M.Row >= Row) + if (M.Row < Row + Rows) { + M.Row = Row; + M.Col = 0; + } else M.Row -= Rows; + } + } + break; + case umSplitLine: + switch (BlockMode) { + case bmLine: + case bmColumn: + if (M.Row == Row) { + if (Col <= M.Col) { + M.Row++; + M.Col -= Col; + } + } else if (M.Row > Row) M.Row++; + break; + case bmStream: + if (M.Row == Row) { + if (Col <= M.Col) { + M.Row++; + M.Col -= Col; + } + } else if (M.Row > Row) M.Row++; + break; + } + break; + case umJoinLine: + switch (BlockMode) { + case bmLine: + case bmColumn: + if (M.Row == Row + 1) + M.Row--; + else if (M.Row > Row) M.Row--; + break; + case bmStream: + if (M.Row == Row + 1) { + M.Row--; + M.Col += Col; + } else if (M.Row > Row) M.Row--; + break; + } + break; + } + return 1; +} + +int EBuffer::UpdateMarker(int Type, int Row, int Col, int Rows, int Cols) { + EPoint OldBB = BB, OldBE = BE; + EView *V; + + UpdateMark(SavedPos, Type, Row, Col, Rows, Cols); + UpdateMark(PrevPos, Type, Row, Col, Rows, Cols); + + UpdateMark(BB, Type, Row, Col, Rows, Cols); + UpdateMark(BE, Type, Row, Col, Rows, Cols); + + V = View; + while (V) { + if (V->Model != this) + assert(1 == 0); + if (V != View) { + EPoint M; + + M = GetViewVPort(V)->TP; + UpdateMark(GetViewVPort(V)->TP, Type, Row, Col, Rows, Cols); + GetViewVPort(V)->TP.Col = M.Col; + UpdateMark(GetViewVPort(V)->CP, Type, Row, Col, Rows, Cols); + } + V = V->NextView; + } + +#ifdef CONFIG_OBJ_ROUTINE + for (int i = 0; i < rlst.Count && rlst.Lines; i++) { + EPoint M; + + M.Col = 0; + M.Row = rlst.Lines[i]; + UpdateMark(M, Type, Row, Col, Rows, Cols); + rlst.Lines[i] = M.Row; + } +#endif + + for (int f = 0; f < FCount; f++) { + EPoint M; + + M.Col = 0; + M.Row = FF[f].line; + UpdateMark(M, Type, Row, Col, Rows, Cols); + FF[f].line = M.Row; + } + +#ifdef CONFIG_BOOKMARKS + for (int b = 0; b < BMCount; b++) + UpdateMark(BMarks[b].BM, Type, Row, Col, Rows, Cols); +#endif + + if (OldBB.Row != BB.Row) { + int MinL = Min(OldBB.Row, BB.Row); + int MaxL = Max(OldBB.Row, BB.Row); + if (MinL != -1 && MaxL != -1) + Draw(MinL, MaxL); + } + if (OldBE.Row != BE.Row) { + int MinL = Min(OldBE.Row, BE.Row); + int MaxL = Max(OldBE.Row, BE.Row); + if (MinL != -1 && MaxL != -1) + Draw(MinL, MaxL); + } + return 1; +} + +int EBuffer::ValidPos(EPoint Pos) { + if ((Pos.Col >= 0) && + (Pos.Row >= 0) && + (Pos.Row < VCount)) + return 1; + return 0; +} + +int EBuffer::RValidPos(EPoint Pos) { + if ((Pos.Col >= 0) && + (Pos.Row >= 0) && + (Pos.Row < RCount)) + return 1; + return 0; +} + +int EBuffer::AssertLine(int Row) { + if (Row == RCount) + if (InsLine(RCount, 0) == 0) return 0; + return 1; +} + +int EBuffer::SetFileName(const char *AFileName, const char *AMode) { + FileOk = 0; + + free(FileName); + FileName = strdup(AFileName); + Mode = 0; + if (AMode) + Mode = FindMode(AMode); + if (Mode == 0) + Mode = GetModeForName(AFileName); + assert(Mode != 0); + Flags = (Mode->Flags); +#ifdef CONFIG_SYNTAX_HILIT + HilitProc = 0; + if (Mode && Mode->fColorize) + HilitProc = GetHilitProc(Mode->fColorize->SyntaxParser); +#endif + UpdateTitle(); + return FileName?1:0; +} + +int EBuffer::SetPos(int Col, int Row, int tabMode) { + assert (Col >= 0 && Row >= 0 && Row < VCount); + +#ifdef CONFIG_UNDOREDO + if (BFI(this, BFI_Undo) == 1 && BFI(this, BFI_UndoMoves) == 1) { + if (PushULong(CP.Col) == 0) return 0; + if (PushULong(CP.Row) == 0) return 0; + if (PushUChar(ucPosition) == 0) return 0; + } +#endif + if (AutoExtend) { + BlockExtendBegin(); + AutoExtend = 1; + } + PrevPos = CP; + PrevPos.Row = (CP.Row < VCount) ? VToR(CP.Row) : (CP.Row - VCount + RCount); + CP.Row = Row; + CP.Col = Col; + if (AutoExtend) { + BlockExtendEnd(); + AutoExtend = 1; + } + // if (View && View->Model == this ) { + // View->GetVPort(); + // } + if (BFI(this, BFI_CursorThroughTabs) == 0) { + if (tabMode == tmLeft) { + if (MoveTabStart() == 0) return 0; + } else if (tabMode == tmRight) { + if (MoveTabEnd() == 0) return 0; + } + } + if (ExtendGrab == 0 && AutoExtend == 0 && BFI(this, BFI_PersistentBlocks) == 0) { + if (CheckBlock() == 1) + if (BlockUnmark() == 0) + return 0; + } + return 1; +} + +int EBuffer::SetPosR(int Col, int Row, int tabMode) { + assert (Row >= 0 && Row < RCount && Col >= 0); + + int L = RToV(Row); + + if (L == -1) + if (ExposeRow(Row) == 0) return 0; + + L = RToV(Row); + + return SetPos(Col, L, tabMode); +} + +int EBuffer::SetNearPos(int Col, int Row, int tabMode) { + if (Row >= VCount) Row = VCount - 1; + if (Row < 0) Row = 0; + if (Col < 0) Col = 0; + return SetPos(Col, Row, tabMode); +} + +int EBuffer::SetNearPosR(int Col, int Row, int tabMode) { + if (Row >= RCount) Row = RCount - 1; + if (Row < 0) Row = 0; + if (Col < 0) Col = 0; + return SetPosR(Col, Row, tabMode); +} + +int EBuffer::CenterPos(int Col, int Row, int tabMode) { + assert(Row >= 0 && Row < VCount && Col >= 0); + + if (SetPos(Col, Row, tabMode) == 0) return 0; + if (View && View->Model == this) { + Row -= GetVPort()->Rows / 2; + if (Row < 0) Row = 0; + Col -= GetVPort()->Cols - 8; + if (Col < 0) Col = 0; + if (GetVPort()->SetTop(Col, Row) == 0) return 0; + GetVPort()->ReCenter = 1; + } + return 1; +} + +int EBuffer::CenterPosR(int Col, int Row, int tabMode) { + int L; + + assert(Row >= 0 && Row < RCount && Col >= 0); + + L = RToV(Row); + if (L == -1) + if (ExposeRow(Row) == 0) return 0; + L = RToV(Row); + return CenterPos(Col, L, tabMode); +} + +int EBuffer::CenterNearPos(int Col, int Row, int tabMode) { + if (Row >= VCount) Row = VCount - 1; + if (Row < 0) Row = 0; + if (Col < 0) Col = 0; + return CenterPos(Col, Row, tabMode); +} + +int EBuffer::CenterNearPosR(int Col, int Row, int tabMode) { + if (Row >= RCount) Row = RCount - 1; + if (Row < 0) Row = 0; + if (Col < 0) Col = 0; + return CenterPosR(Col, Row, tabMode); +} + +int EBuffer::LineLen(int Row) { + assert(Row >= 0 && Row < RCount); + PELine L = RLine(Row); + return ScreenPos(L, L->Count); +} + +int EBuffer::LineChars(int Row) { + assert(Row >= 0 && Row < RCount); + return RLine(Row)->Count; +} + +int EBuffer::DelLine(int Row, int DoMark) { + int VLine; + int GapSize; +// printf("DelLine: %d\n", Row); + if (Row < 0) return 0; + if (Row >= RCount) return 0; + if (Modify() == 0) return 0; + + VLine = RToV(Row); + if (VLine == -1) + if (ExposeRow(Row) == 0) return 0; + VLine = RToV(Row); + assert(VLine != -1); + + if (FindFold(Row) != -1) { + if (FoldDestroy(Row) == 0) return 0; + } + + VLine = RToV(Row); + assert(VLine != -1); + +#ifdef CONFIG_UNDOREDO + if (BFI(this, BFI_Undo) == 1) { + if (PushUData(RLine(Row)->Chars, RLine(Row)->Count) == 0) return 0; + if (PushULong(RLine(Row)->Count) == 0) return 0; + if (PushULong(Row) == 0) return 0; + if (PushUChar(ucDelLine) == 0) return 0; + } +#endif + if (DoMark) + UpdateMarker(umDelete, Row, 0, 1, 0); + //puts("Here"); + + Draw(Row, -1); + Hilit(Row); + assert(RAllocated >= RCount); + if (RGap != Row) + if (MoveRGap(Row) == 0) return 0; + + GapSize = RAllocated - RCount; + + delete LL[RGap + GapSize]; + LL[RGap + GapSize] = 0; + RCount--; + GapSize++; + if (RAllocated - RAllocated / 2 > RCount) { + memmove(LL + RGap + GapSize - RAllocated / 3, + LL + RGap + GapSize, + sizeof(PELine) * (RCount - RGap)); + if (Allocate(RAllocated - RAllocated / 3) == 0) return 0; + } + + assert(VAllocated >= VCount); + if (VGap != VLine) + if (MoveVGap(VLine) == 0) return 0; + GapSize = VAllocated - VCount; + VV[VGap + GapSize] = 0; + VCount--; + GapSize++; + if (VAllocated - VAllocated / 2 > VCount) { + memmove(VV + VGap + GapSize - VAllocated / 3, + VV + VGap + GapSize, + sizeof(VV[0]) * (VCount - VGap)); + if (AllocVis(VAllocated - VAllocated / 3) == 0) return 0; + } + return 1; +} + +int EBuffer::InsLine(int Row, int DoAppend, int DoMark) { + PELine L; + int VLine = -1; + + // printf("InsLine: %d\n", Row); + + if (Row < 0) return 0; + if (Row > RCount) return 0; + if (Modify() == 0) return 0; + if (DoAppend) { + Row++; + } + if (Row < RCount) { + VLine = RToV(Row); + if (VLine == -1) + if (ExposeRow(Row) == 0) return 0; + VLine = RToV(Row); + assert(VLine != -1); + } else { + VLine = VCount; + } + L = new ELine(0, (char *)0); + if (L == 0) return 0; +#ifdef CONFIG_UNDOREDO + if (BFI(this, BFI_Undo) == 1) { + if (PushULong(Row) == 0) return 0; + if (PushUChar(ucInsLine) == 0) return 0; + } +#endif + if (DoMark) + UpdateMarker(umInsert, Row, 0, 1, 0); + Draw(Row, -1); + Hilit(Row); + VLine = RToVN(Row); + assert(RCount <= RAllocated); +// printf("++ %d G:C:A :: %d - %d - %d\n", Row, RGap, RCount, RAllocated); + if (RCount == RAllocated) { + if (Allocate(RCount ? (RCount * 2) : 1) == 0) return 0; + memmove(LL + RAllocated - (RCount - RGap), + LL + RGap, + sizeof(PELine) * (RCount - RGap)); + } + if (RGap != Row) + if (MoveRGap(Row) == 0) return 0; + LL[RGap] = L; + RGap++; + RCount++; + // printf("-- %d G:C:A :: %d - %d - %d\n", Row, RGap, RCount, RAllocated); + + assert(VCount <= VAllocated); + if (VCount == VAllocated) { + if (AllocVis(VCount ? (VCount * 2) : 1) == 0) return 0; + memmove(VV + VAllocated - (VCount - VGap), + VV + VGap, + sizeof(VV[0]) * (VCount - VGap)); + } + if (VGap != VLine) + if (MoveVGap(VLine) == 0) return 0; + VV[VGap] = Row - VGap; + VGap++; + VCount++; + +/* if (AllocVis(VCount + 1) == 0) return 0; + memmove(VV + VLine + 1, VV + VLine, sizeof(VV[0]) * (VCount - VLine)); + VCount++; + Vis(VLine, Row - VLine);*/ + return 1; +} + +int EBuffer::DelChars(int Row, int Ofs, int ACount) { + PELine L; + +// printf("DelChars: %d:%d %d\n", Row, Ofs, ACount); + if (Row < 0) return 0; + if (Row >= RCount) return 0; + L = RLine(Row); + + if (Ofs < 0) return 0; + if (Ofs >= L->Count) return 0; + if (Ofs + ACount >= L->Count) + ACount = L->Count - Ofs; + if (ACount == 0) return 1; + + if (Modify() == 0) return 0; + +#ifdef CONFIG_UNDOREDO + if (BFI(this, BFI_Undo) == 1) { + if (PushUData(L->Chars + Ofs, ACount) == 0) return 0; + if (PushULong(ACount) == 0) return 0; + if (PushULong(Ofs) == 0) return 0; + if (PushULong(Row) == 0) return 0; + if (PushUChar(ucDelChars) == 0) return 0; + } +#endif + + if (L->Count > Ofs + ACount) + memmove(L->Chars + Ofs, L->Chars + Ofs + ACount, L->Count - Ofs - ACount); + L->Count -= ACount; + if (L->Allocate(L->Count) == 0) return 0; + Draw(Row, Row); + Hilit(Row); +// printf("OK\n"); + return 1; +} + +int EBuffer::InsChars(int Row, int Ofs, int ACount, char *Buffer) { + PELine L; + +// printf("InsChars: %d:%d %d\n", Row, Ofs, ACount); + + assert(Row >= 0 && Row < RCount && Ofs >= 0); + L = RLine(Row); + + if (Ofs < 0) return 0; + if (Ofs > L->Count) return 0; + if (ACount == 0) return 1; + + if (Modify() == 0) return 0; + +#ifdef CONFIG_UNDOREDO + if (BFI(this, BFI_Undo) == 1) { + if (PushULong(Row) == 0) return 0; + if (PushULong(Ofs) == 0) return 0; + if (PushULong(ACount) == 0) return 0; + if (PushUChar(ucInsChars) == 0) return 0; + } +#endif + if (L->Allocate(L->Count + ACount) == 0) return 0; + if (L->Count > Ofs) + memmove(L->Chars + Ofs + ACount, L->Chars + Ofs, L->Count - Ofs); + if (Buffer == 0) + memset(L->Chars + Ofs, ' ', ACount); + else + memmove(L->Chars + Ofs, Buffer, ACount); + L->Count += ACount; + Draw(Row, Row); + Hilit(Row); + // printf("OK\n"); + return 1; +} + +int EBuffer::UnTabPoint(int Row, int Col) { + ELine *L; + int Ofs, Pos, TPos; + + assert(Row >= 0 && Row < RCount && Col >= 0); + L = RLine(Row); + Ofs = CharOffset(L, Col); + if (Ofs >= L->Count) + return 1; + if (L->Chars[Ofs] != '\t') + return 1; + Pos = ScreenPos(L, Ofs); + if (Pos < Col) { + TPos = NextTab(Pos, BFI(this, BFI_TabSize)); + if (DelChars(Row, Ofs, 1) != 1) + return 0; + if (InsChars(Row, Ofs, TPos - Pos, 0) != 1) + return 0; + } + return 1; +} + +int EBuffer::ChgChars(int Row, int Ofs, int ACount, char * /*Buffer*/) { + PELine L; + + assert(Row >= 0 && Row < RCount && Ofs >= 0); + L = RLine(Row); + + if (Ofs < 0) return 0; + if (Ofs > L->Count) return 0; + if (ACount == 0) return 1; + + if (Modify() == 0) return 0; + +#ifdef CONFIG_UNDOREDO + if (BFI(this, BFI_Undo) == 1) { + if (PushUData(L->Chars + Ofs, ACount) == 0) return 0; + if (PushULong(ACount) == 0) return 0; + if (PushULong(Ofs) == 0) return 0; + if (PushULong(Row) == 0) return 0; + if (PushUChar(ucDelChars) == 0) return 0; + if (PushULong(Row) == 0) return 0; + if (PushULong(Ofs) == 0) return 0; + if (PushULong(ACount) == 0) return 0; + if (PushUChar(ucInsChars) == 0) return 0; + } +#endif + Hilit(Row); + Draw(Row, Row); + return 1; +} + +int EBuffer::DelText(int Row, int Col, int ACount, int DoMark) { + int L, B, C; + +// printf("DelTExt: %d:%d %d\n", Row, Col, ACount); + + assert(Row >= 0 && Row < RCount && Col >= 0); + if (Modify() == 0) return 0; + + if (ACount == 0) return 1; + L = LineLen(Row); + if (Col >= L) + return 1; + if (ACount == -1 || ACount + Col > L) + ACount = L - Col; + if (UnTabPoint(Row, Col) == 0) + return 0; + if (UnTabPoint(Row, Col + ACount) == 0) + return 0; + B = CharOffset(RLine(Row), Col); + C = CharOffset(RLine(Row), Col + ACount); + if ((ACount > 0) && (B != -1) && (C != -1)) { + if (DelChars(Row, B, C - B) == 0) return 0; + if (DoMark) UpdateMarker(umDelete, Row, Col, 0, ACount); + } +// printf("OK\n"); + return 1; +} + +int EBuffer::InsText(int Row, int Col, int ACount, char *ABuffer, int DoMark) { + int B, L; + +// printf("InsText: %d:%d %d\n", Row, Col, ACount); + assert(Row >= 0 && Row < RCount && Col >= 0 && ACount >= 0); + if (ACount == 0) return 1; + if (Modify() == 0) return 0; + + if (DoMark) UpdateMarker(umInsert, Row, Col, 0, ACount); + L = LineLen(Row); + if (L < Col) { + if (InsChars(Row, RLine(Row)->Count, Col - L, 0) == 0) + return 0; + } else + if (UnTabPoint(Row, Col) == 0) return 0; + B = CharOffset(RLine(Row), Col); + if (InsChars(Row, B, ACount, ABuffer) == 0) return 0; +// printf("OK\n"); + return 1; +} + +int EBuffer::PadLine(int Row, int Length) { + int L; + + L = LineLen(Row); + if (L < Length) + if (InsChars(Row, RLine(Row)->Count, Length - L, 0) == 0) + return 0; + return 1; +} + +int EBuffer::InsLineText(int Row, int Col, int ACount, int LCol, PELine Line) { + int Ofs, Pos, TPos, C, B, L; + + //fprintf(stderr, "\n\nInsLineText: %d:%d %d %d", Row, Col, ACount, LCol); + assert(Row >= 0 && Row < RCount && Col >= 0 && LCol >= 0); + if (BFI(this, BFI_ReadOnly) == 1) + return 0; + + L = ScreenPos(Line, Line->Count); + if (LCol >= L) return 1; + if (ACount == -1) ACount = L - LCol; + if (ACount + LCol > L) ACount = L - LCol; + if (ACount == 0) return 1; + assert(ACount > 0); + + B = Ofs = CharOffset(Line, LCol); + if (Ofs < Line->Count && Line->Chars[Ofs] == '\t') { + Pos = ScreenPos(Line, Ofs); + if (Pos < LCol) { + TPos = NextTab(Pos, BFI(this, BFI_TabSize)); + if (InsText(Row, Col, TPos - LCol, 0) == 0) + return 0; + Col += TPos - LCol; + ACount -= TPos - LCol; + LCol = TPos; + B++; + } + } + C = Ofs = CharOffset(Line, LCol + ACount); + if (Ofs < Line->Count && Line->Chars[Ofs] == '\t') { + Pos = ScreenPos(Line, Ofs); + if (Pos < LCol + ACount) { + if (InsText(Row, Col, LCol + ACount - Pos, 0) == 0) + return 0; + } + } + //fprintf(stderr, "B = %d, C = %d\n", B, C); + C -= B; + if (C <= 0) return 1; + if (InsText(Row, Col, C, Line->Chars + B) == 0) return 0; +// printf("OK\n"); + return 1; +} + +int EBuffer::SplitLine(int Row, int Col) { + int VL; + + assert(Row >= 0 && Row < RCount && Col >= 0); + + if (BFI(this, BFI_ReadOnly) == 1) return 0; + + VL = RToV(Row); + if (VL == -1) + if (ExposeRow(Row) == 0) return 0; + if (Row > 0) { + VL = RToV(Row - 1); + if (VL == -1) + if (ExposeRow(Row - 1) == 0) return 0; + } + VL = RToV(Row); + assert(VL != -1); + if (Col == 0) { + if (InsLine(Row, 0, 1) == 0) return 0; + } else { + UpdateMarker(umSplitLine, Row, Col, 0, 0); + if (InsLine(Row, 1, 0) == 0) return 0; + RLine(Row)->StateE = short((Row > 0) ? RLine(Row - 1)->StateE : 0); + if (Col < LineLen(Row)) { + int P, L; + //if (RLine(Row)->ExpandTabs(Col, -2, &Flags) == 0) return 0; + if (UnTabPoint(Row, Col) != 1) + return 0; + + P = CharOffset(RLine(Row), Col); + L = LineLen(Row); + + if (InsText(Row + 1, 0, RLine(Row)->Count - P, RLine(Row)->Chars + P, 0) == 0) return 0; + if (DelText(Row, Col, L - Col, 0) == 0) return 0; + } + } + Draw(Row, -1); + Hilit(Row); + return 1; +} + +int EBuffer::JoinLine(int Row, int Col) { + int Len, VLine; + + if (BFI(this, BFI_ReadOnly) == 1) return 0; + if (Row < 0 || Row >= RCount - 1) return 0; + if (Col < 0) return 0; + Len = LineLen(Row); + if (Col < Len) Col = Len; + VLine = RToV(Row); + if (VLine == -1) { + if (ExposeRow(Row) == 0) return 0; + if (ExposeRow(Row + 1) == 0) return 0; + } + VLine = RToV(Row); + if (Col == 0 && RLine(Row)->Count == 0) { + if (DelLine(Row, 1) == 0) return 0; + } else { + if (InsText(Row, Col, RLine(Row + 1)->Count, RLine(Row + 1)->Chars, 0) == 0) return 0; + if (DelLine(Row + 1, 0) == 0) return 0; + UpdateMarker(umJoinLine, Row, Col, 0, 0); + } + Draw(Row, -1); + Hilit(Row); + return 1; +} diff --git a/src/e_buffer.h b/src/e_buffer.h new file mode 100644 index 0000000..9c53aba --- /dev/null +++ b/src/e_buffer.h @@ -0,0 +1,770 @@ +/* e_buffer.h + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#ifndef _BUFFER_H_ +#define _BUFFER_H_ + +#define bmLine 0 +#define bmStream 1 +#define bmColumn 2 + +#define E_OK 0 // all ok +#define E_CANCEL 1 // operation cancelled +#define E_ERROR 2 // error +#define E_NOMEM 3 // out of memory + +#define umDelete 0 +#define umInsert 1 +#define umSplitLine 2 +#define umJoinLine 3 + +#define tmNone 0 +#define tmLeft 1 +#define tmRight 2 + +typedef unsigned char TransTable[256]; + +#ifdef DOS /* 16 bit, sometime ;-) */ +#define RWBUFSIZE 8192 +#else +#define RWBUFSIZE 32768 +#endif + +extern char FileBuffer[RWBUFSIZE]; + +#define ChClass(x) (WGETBIT(Flags.WordChars, (x)) ? 1 : 0) +#define ChClassK(x) (((x) == ' ' || (x) == 9) ? 2 : ChClass(x)) + +#define InRange(a,x,b) (((a) <= (x)) && ((x) < (b))) +#define Min(a,b) (((a) < (b))?(a):(b)) +#define Max(a,b) (((a) > (b))?(a):(b)) + +#define NextTab(pos,ts) (((pos) / (ts) + 1) * (ts)) + +#define GapLine(x,g,c,a) (((x) < (g)) ? (x) : ((x) + (a) - (c))) + +typedef class ELine* PELine; +typedef class EPoint* PEPoint; + +#define CHAR_TRESHOLD 0x3U + +class ELine { +public: + int Count; + char *Chars; +#ifdef CONFIG_SYNTAX_HILIT + hlState StateE; +#endif + + ELine(int ACount, char *AChars); + ELine(char *AChars, int ACount); + ~ELine(); + int Allocate(unsigned int Bytes); + +// int Length(EBufferFlags *CurFlags); +}; + +class EPoint { +public: + int Row; + int Col; + +// EPoint(EPoint &M) { Row = M.Row; Col = M.Col; } + EPoint(int aRow = 0, int aCol = 0) { Row = aRow; Col = aCol; } + ~EPoint() {} +}; + +typedef struct _UndoStack { + int NextCmd, Record, Undo; + int UndoPtr; + int Num; + void **Data; + int *Top; +} UndoStack; + +#ifdef CONFIG_OBJ_ROUTINE +class RoutineView; + +typedef struct _RoutineList { + int Count; + int *Lines; +} RoutineList; +#endif + +#ifdef CONFIG_BOOKMARKS +typedef struct { + char *Name; + EPoint BM; +} EBookmark; +#endif + +typedef struct { + int line; + unsigned char level; + unsigned char open; + unsigned short flags; +} EFold; + +class EEditPort: public EViewPort { +public: + EBuffer *Buffer; + EPoint TP, OldTP; + EPoint CP; + int Rows, Cols; + + EEditPort(EBuffer *B, EView *V); + virtual ~EEditPort(); + + virtual void HandleEvent(TEvent &Event); + virtual void HandleMouse(TEvent &Event); + virtual void UpdateView(); + virtual void RepaintView(); + virtual void UpdateStatus(); + virtual void RepaintStatus(); + + virtual void Resize(int Width, int Height); + int SetTop(int Col, int Row); + virtual void GetPos(); + virtual void StorePos(); + void DrawLine(int L, TDrawBuffer B); + void ScrollY(int Delta); + void RedrawAll(); +}; + +class EBuffer: public EModel { +public: + //char *Name; + char *FileName; + int Modified; + EPoint TP; + EPoint CP; + EPoint BB; + EPoint BE; + EPoint PrevPos; + EPoint SavedPos; + + EBufferFlags Flags; + EMode *Mode; + int BlockMode; + int ExtendGrab; + int AutoExtend; + int Loaded; + +#ifdef CONFIG_UNDOREDO + UndoStack US; +#endif + + struct stat FileStatus; + int FileOk; + int Loading; + + int RAllocated; // text line allocation + int RGap; + int RCount; + PELine *LL; + + int VAllocated; // visible lines + int VGap; + int VCount; + int *VV; + +#ifdef CONFIG_FOLDS + int FCount; + EFold *FF; +#endif + + EPoint Match; + int MatchLen; + int MatchCount; + RxMatchRes MatchRes; + +#ifdef CONFIG_BOOKMARKS + int BMCount; + EBookmark *BMarks; +#endif + +#ifdef CONFIG_OBJ_ROUTINE + RoutineList rlst; + RoutineView *Routines; +#endif + + int MinRedraw, MaxRedraw; + int RedrawToEos; + +#ifdef CONFIG_WORD_HILIT + char **WordList; + int WordCount; +#endif +#ifdef CONFIG_SYNTAX_HILIT + SyntaxProc HilitProc; + int StartHilit, EndHilit; +#endif + + // constructors + EBuffer(int createFlags, EModel **ARoot, const char *AName); + ~EBuffer(); + virtual void DeleteRelated(); + + virtual EViewPort *CreateViewPort(EView *V); + EEditPort *GetViewVPort(EView *V); + EEditPort *GetVPort(); + virtual int CanQuit(); + virtual int ConfQuit(GxView *V, int multiFile = 0); + + virtual int GetContext(); + virtual EEventMap *GetEventMap(); + virtual int BeginMacro(); + virtual int ExecCommand(int Command, ExState &State); + virtual void HandleEvent(TEvent &Event); + + virtual void GetName(char *AName, int MaxLen); + virtual void GetPath(char *APath, int MaxLen); + virtual void GetInfo(char *AInfo, int MaxLen); + virtual void GetTitle(char *ATitle, int MaxLen, char *ASTitle, int SMaxLen); + + PELine RLine(int No) { +#ifdef DEBUG_EDITOR + int N = GapLine(No, RGap, RCount, RAllocated); + if (!((No < RCount) && (No >= 0) && (LL[N]))) { + printf("Get No = %d/%d Gap=%d RAlloc = %d, VCount = %d\n", No, RCount, RGap, RAllocated, VCount); + assert((No < RCount) && (No >= 0) && (LL[N])); + } +#endif + return LL[GapLine(No, RGap, RCount, RAllocated)]; + } + void RLine(int No, PELine L) { +#ifdef DEBUG_EDITOR + if (!((No >= 0))) printf("Set No = %d\n", No); + assert((No >= 0)); +#endif + LL[GapLine(No, RGap, RCount, RAllocated)] = L; + } + int Vis(int No) { +#ifdef DEBUG_EDITOR + if (No < 0 || No >= VCount) { + printf("Vis get no %d of %d\n", No, VCount); + assert (No >= 0 && No < VCount); + } +#endif + return VV[GapLine(No, VGap, VCount, VAllocated)]; + } + void Vis(int No, int V) { +#ifdef DEBUG_EDITOR + if (No < 0 || No >= VCount) { + printf("Vis set no %d of %d to %d\n", No, VCount, V); + assert (No >= 0 && No < VCount); + } +#endif + VV[GapLine(No, VGap, VCount, VAllocated)] = V; + } + PELine VLine(int No) { +#ifdef DEBUG_EDITOR + if (!((No < VCount) && (No >= 0))) { + printf("VGet No = %d\n", No); + assert((No < VCount) && (No >= 0)); + } + if (Vis(No) < 0) + assert(1 == 0); +#endif + return RLine(No + Vis(No)); + } + void VLine(int No, PELine L) { +#ifdef DEBUG_EDITOR + if (!((No >= 0))) { + printf("VSet No = %d\n", No); + assert((No >= 0)); + } + if (VV[No] < 0) + assert(1 == 0); +#endif + RLine(No + Vis(No), L); + } + + int VToR(int No) { +#ifdef DEBUG_EDITOR + if (!(No < VCount)) { + printf("Get No = %d\n", No); + assert((No < VCount)); + } +#endif + return No + Vis(No); + } + + int RToV(int No); + int RToVN(int No); + + // allocation + int Allocate(int ACount); + int MoveRGap(int RPos); + int AllocVis(int ACount); + int MoveVGap(int VPos); + + int Modify(); + int Clear(); + +#ifdef CONFIG_UNDOREDO + int FreeUndo(); +#endif + // internal primitives + int ValidPos(EPoint W); + int RValidPos(EPoint W); + int LoadRegion(EPoint *A, int FH, int StripChar, int LineChar); + int SaveRegion(EPoint *A, EPoint *Z, int FH, int AddCR, int AddLF, int Mode); + + int AssertLine(int Line); + int InsertLine(EPoint Pos, int ACount, char *AChars); + + int UpdateMarker(int Type, int Line, int Col, int Lines, int Cols); + int UpdateMark(EPoint &M, int Type, int Line, int Col, int Lines, int Cols); + void UpdateVis(EPoint &M, int Row, int Delta); + void UpdateVisible(int Row, int Delta); + int LoadFrom(char *AFileName); + int SaveTo(char *AFileName); + + int IsBlockStart(); + int IsBlockEnd(); + int BlockType(int Mode); + int BeginExtend(); + int EndExtend(); + int CheckBlock(); + int BlockRedraw(); + int SetBB(EPoint M); + int SetBE(EPoint M); + + int Load(); + int Save(); + int Reload(); + int FilePrint(); + int SetFileName(const char *AFileName, const char *AMode); + + int SetPos(int Col, int Row, int tabMode = tmNone); + int SetPosR(int Col, int Row, int tabMode = tmNone); + int CenterPos(int Col, int Row, int tabMode = tmNone); + int CenterPosR(int Col, int Row, int tabMode = tmNone); + int SetNearPos(int Col, int Row, int tabMode = tmNone); + int SetNearPosR(int Col, int Row, int tabMode = tmNone); + int CenterNearPos(int Col, int Row, int tabMode = tmNone); + int CenterNearPosR(int Col, int Row, int tabMode = tmNone); + int LineLen(int Row); + int LineChars(int Row); + +///////////////////////////////////////////////////////////////////////////// +// Undo/Redo Routines +///////////////////////////////////////////////////////////////////////////// + + int NextCommand(); +#ifdef CONFIG_UNDOREDO + int PushUData(void *data, int len); + int PushULong(unsigned long l); + int PushUChar(unsigned char ch); + int PopUData(void *data, int len); + int GetUData(int No, int pos, void **data, int len); + int Undo(int undo); + int Undo(); + int Redo(); + int BeginUndo(); + int EndUndo(); + int PushBlockData(); +#endif + +///////////////////////////////////////////////////////////////////////////// +// Primitive Editing +///////////////////////////////////////////////////////////////////////////// + + //int ExpReg(int Row, int Ofs, int ACount, int &B, int &E); + int ScreenPos(ELine *L, int Offset); + int CharOffset(ELine *L, int ScreenPos); + int DelLine(int Row, int DoMark = 1); + int UnTabPoint(int Row, int Col); + int InsLine(int Row, int DoAppend, int DoMark = 1); + int DelChars(int Row, int Ofs, int ACount); + int InsChars(int Row, int Ofs, int ACount, char *Buffer); + int ChgChars(int Row, int Ofs, int ACount, char *Buffer); + int DelText(int Row, int Col, int ACount, int DoMark = 1); + int InsText(int Row, int Col, int ACount, char *Buffer, int DoMark = 1); + int InsLineText(int Row, int Col, int ACount, int Pos, PELine Line); + int SplitLine(int Row, int Col); + int JoinLine(int Row, int Col); + int CanUnfold(int Row); + int PadLine(int Row, int Length); + + int ShowRow(int Row); + int HideRow(int Row); + int ExposeRow(int Row); // make row visible (open all folds containing) + +///////////////////////////////////////////////////////////////////////////// +// Redraw/Windowing Routines +///////////////////////////////////////////////////////////////////////////// + + void Draw(int Line0, int LineE); + void DrawLine(TDrawBuffer B, int L, int C, int W, int &HilitX); + void Hilit(int FromRow); + void Rehilit(int ToRow); + void Redraw(); + void FullRedraw(); + int GetHilitWord(int len, char *str, ChColor &clr, int IgnCase = 0); + +///////////////////////////////////////////////////////////////////////////// +// Utility Routines +///////////////////////////////////////////////////////////////////////////// + + int LineIndented(int Row); + int IndentLine(int Row, int Indent); +#ifdef CONFIG_SYNTAX_HILIT + int GetMap(int Row, int *StateLen, hsState **StateMap); +#endif + int FindStr(char *Data, int Len, int Options); + int FindRx(RxNode *Rx, int Options); + int Find(SearchReplaceOptions &opt); + int IsLineBlank(int Row); + int TrimLine(int Row); + +#ifdef CONFIG_OBJ_ROUTINE + int ScanForRoutines(); +#endif + +///////////////////////////////////////////////////////////////////////////// +// Bookmark Routines +///////////////////////////////////////////////////////////////////////////// + +#ifdef CONFIG_BOOKMARKS + int PlaceBookmark(char *Name, EPoint P); + int RemoveBookmark(char *Name); + int GetBookmark(char *Name, EPoint &P); + int GotoBookmark(char *Name); +#endif + +///////////////////////////////////////////////////////////////////////////// +// Editing Routines +///////////////////////////////////////////////////////////////////////////// + + int MoveLeft(); + int MoveRight(); + int MoveUp(); + int MoveDown(); + int MovePrev(); + int MoveNext(); + int MoveWordLeftX(int start); + int MoveWordRightX(int start); + int MoveWordLeft(); + int MoveWordRight(); + int MoveWordPrev(); + int MoveWordNext(); + int MoveWordEndLeft(); + int MoveWordEndRight(); + int MoveWordEndPrev(); + int MoveWordEndNext(); + int MoveWordOrCapLeft(); + int MoveWordOrCapRight(); + int MoveWordOrCapPrev(); + int MoveWordOrCapNext(); + int MoveWordOrCapEndLeft(); + int MoveWordOrCapEndRight(); + int MoveWordOrCapEndPrev(); + int MoveWordOrCapEndNext(); +// int MoveWordStart(); +// int MoveWordEnd(); + int MoveLineStart(); + int MoveLineEnd(); + int MovePageUp(); + int MovePageDown(); + int MovePageLeft(); + int MovePageRight(); + int MovePageStart(); + int MovePageEnd(); + int MoveFileStart(); + int MoveFileEnd(); + int MoveBlockStart(); + int MoveBlockEnd(); + int ScrollLeft(int Cols); + int ScrollRight(int Cols); + int ScrollDown(int Lines); + int ScrollUp(int Lines); + int MoveToLine(); + int MoveToColumn(); + int MoveFirstNonWhite(); + int MoveLastNonWhite(); + int MovePrevEqualIndent(); + int MoveNextEqualIndent(); + int MovePrevTab(); + int MoveNextTab(); + int MoveLineTop(); + int MoveLineCenter(); + int MoveLineBottom(); + int MovePrevPos(); + int MoveSavedPosCol(); + int MoveSavedPosRow(); + int MoveSavedPos(); + int SavePos(); + int MoveTabStart(); + int MoveTabEnd(); + int MoveFoldTop(); + int MoveFoldPrev(); + int MoveFoldNext(); + int MoveBeginOrNonWhite(); + int MoveBeginLinePageFile(); + int MoveEndLinePageFile(); + + int KillLine(); + int KillChar(); + int KillCharPrev(); + int KillWord(); + int KillWordPrev(); + int KillWordOrCap(); + int KillWordOrCapPrev(); + int KillToLineStart(); + int KillToLineEnd(); + int KillBlock(); + int BackSpace(); + int Delete(); + int CompleteWord(); + int KillBlockOrChar(); + int KillBlockOrCharPrev(); + +#define ccUp 0 +#define ccDown 1 +#define ccToggle 2 + + int CharTrans(TransTable tab); + int CharCaseUp(); + int CharCaseDown(); + int CharCaseToggle(); + + int LineTrans(TransTable tab); + int LineCaseUp(); + int LineCaseDown(); + int LineCaseToggle(); + + int BlockTrans(TransTable tab); + int BlockCaseUp(); + int BlockCaseDown(); + int BlockCaseToggle(); + + int CharTrans(ExState &State); + int LineTrans(ExState &State); + int BlockTrans(ExState &State); + int GetTrans(ExState &State, TransTable tab); + + int LineInsert(); + int LineAdd(); + int LineSplit(); + int LineJoin(); + int LineNew(); + int LineIndent(); + int LineTrim(); + int LineCenter(); + int FileTrim(); + int BlockTrim(); + +#ifdef CONFIG_UNDOREDO + int CanUndo(); + int CanRedo(); +#endif + + int LineLen(); + int LineCount(); + int CLine(); + int CColumn(); + + int InsertChar(char aCh); + int TypeChar(char aCh); + int InsertString(char *aStr, int aCount); + int InsertSpacesToTab(int TSize); + int InsertTab(); + int InsertSpace(); + int SelfInsert(); +#ifdef CONFIG_WORDWRAP + int DoWrap(int WrapAll); + int WrapPara(); +#endif + int InsPrevLineChar(); + int InsPrevLineToEol(); + int LineDuplicate(); + + int GetMatchBrace(EPoint &M, int MinLine, int MaxLine, int show); + int MatchBracket(); + int HilitMatchBracket(); + + int BlockBegin(); + int BlockEnd(); + int BlockUnmark(); + int BlockCut(int Append); + int BlockCopy(int Append); + int BlockPaste(); + int BlockKill(); + int BlockIndent(); + int BlockUnindent(); + int BlockClear(); + int BlockMarkStream(); + int BlockMarkLine(); + int BlockMarkColumn(); + int BlockReadFrom(char *aFileName, int blockMode); + int BlockWriteTo(char *aFileName, int Append = 0); + int BlockExtendBegin(); + int BlockExtendEnd(); + int BlockReIndent(); + int BlockIsMarked(); + int BlockPasteStream(); + int BlockPasteLine(); + int BlockPasteColumn(); + int BlockSelectWord(); + int BlockSelectLine(); + int BlockSelectPara(); + int BlockPrint(); + int BlockSort(int Reverse); + int ClipClear(); + int BlockUnTab(); + int BlockEnTab(); + + int ToggleAutoIndent(); + int ToggleInsert(); + int ToggleExpandTabs(); + int ToggleShowTabs(); + int ToggleUndo(); + int ToggleReadOnly(); + int ToggleKeepBackups(); + int ToggleMatchCase(); + int ToggleBackSpKillTab(); + int ToggleDeleteKillTab(); + int ToggleSpaceTabs(); + int ToggleIndentWithTabs(); + int ToggleBackSpUnindents(); + int ToggleWordWrap(); + int ToggleTrim(); + int ToggleShowMarkers(); + + int SetLeftMargin(); + int SetRightMargin(); + + int ShowPosition(); + + int Search(ExState &State, char *aString, int Options, int CanResume = 0); + int SearchAgain(ExState &State, unsigned int Options); + int SearchReplace(ExState &State, char *aString, char *aReplaceString, int Options); + int Search(ExState &State); + int SearchB(ExState &State); + int SearchRx(ExState &State); + int SearchAgain(ExState &State); + int SearchAgainB(ExState &State); + int SearchReplace(ExState &State); + int SearchReplaceB(ExState &State); + int SearchReplaceRx(ExState &State); + +#ifdef CONFIG_WORD_HILIT + int HilitAddWord(const char *Word); + int HilitFindWord(const char *Word); + int HilitRemoveWord(const char *Word); + int HilitWord(); +#endif + int SearchWord(int Flags); + +#ifdef CONFIG_FOLDS + int FindFold(int Line); + int FindNearFold(int Line); + int FoldCreate(int Line); + int FoldCreateByRegexp(char *Regexp); + int FoldDestroy(int Line); + int FoldDestroyAll(); + int FoldPromote(int Line); + int FoldDemote(int Line); + int FoldOpen(int Line); + int FoldOpenAll(); + int FoldOpenNested(); + int FoldClose(int Line); + int FoldCloseAll(); + int FoldToggleOpenClose(); +#endif + + int ChangeMode(char *Mode); + int ChangeKeys(char *Mode); + int ChangeFlags(char *Mode); + + int ScrollLeft(ExState &State); + int ScrollRight(ExState &State); + int ScrollDown(ExState &State); + int ScrollUp(ExState &State); + + /* editor functions with user interface */ + + int MoveToColumn(ExState &State); + int MoveToLine(ExState &State); + int FoldCreateByRegexp(ExState &State); +#ifdef CONFIG_BOOKMARKS + int PlaceBookmark(ExState &State); + int RemoveBookmark(ExState &State); + int GotoBookmark(ExState &State); +#endif + int InsertString(ExState &State); + int SelfInsert(ExState &State); + int FileReload(ExState &State); + int FileSaveAs(char *FileName); + int FileSaveAs(ExState &State); + int FileWriteTo(char *FileName); + int FileWriteTo(ExState &State); + int BlockReadX(ExState &State, int BlockMode); + int BlockRead(ExState &State); + int BlockReadStream(ExState &State); + int BlockReadLine(ExState &State); + int BlockReadColumn(ExState &State); + int BlockWrite(ExState &State); + int Find(ExState &State); + int FindReplace(ExState &State); + int FindRepeat(ExState &State); + int FindRepeatOnce(ExState &State); + int FindRepeatReverse(ExState &State); + int InsertChar(ExState &State); + int TypeChar(ExState &State); + int ChangeMode(ExState &State); + int ChangeKeys(ExState &State); + int ChangeFlags(ExState &State); + int ChangeTabSize(ExState &State); + int ChangeRightMargin(ExState &State); + int ChangeLeftMargin(ExState &State); + +#ifdef CONFIG_I_ASCII + int ASCIITable(ExState &State); +#endif + +#ifdef CONFIG_TAGS + int FindTag(ExState &State); + int FindTagWord(ExState &State); +#endif + + int SetCIndentStyle(ExState &State); + + int FindFunction(int delta, int way); + int BlockMarkFunction(); + int IndentFunction(); + int MoveFunctionPrev(); + int MoveFunctionNext(); + int InsertDate(ExState& state); + int InsertUid(); + + int ShowHelpWord(ExState &State); + + int PlaceGlobalBookmark(ExState &State); + int PushGlobalBookmark(); + + virtual int GetStrVar(int var, char *str, int buflen); + virtual int GetIntVar(int var, int *value); + + int SetIndentWithTabs(ExState &State); + int FoldCreateAtRoutines(); +}; + +extern EBuffer *SSBuffer; +extern SearchReplaceOptions LSearch; + +extern int suspendLoads; + +int DoneEditor(); + +EBuffer *FindFile(char *FileName); + +#endif diff --git a/src/e_cmds.cpp b/src/e_cmds.cpp new file mode 100644 index 0000000..2993e8b --- /dev/null +++ b/src/e_cmds.cpp @@ -0,0 +1,1346 @@ +/* e_cmds.cpp + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#include "fte.h" + +int EBuffer::MoveLeft() { + if (CP.Col == 0) return 0; + SetPos(CP.Col - 1, CP.Row, tmLeft); + return 1; +} + +int EBuffer::MoveRight() { + SetPos(CP.Col + 1, CP.Row, tmRight); + return 1; +} + +int EBuffer::MoveUp() { + if (CP.Row == 0) return 0; + SetPos(CP.Col, CP.Row - 1, tmLeft); + return 1; +} + +int EBuffer::MoveDown() { + if (CP.Row == VCount - 1) return 0; + SetPos(CP.Col, CP.Row + 1, tmLeft); + return 1; +} + +int EBuffer::MovePrev() { + if (MoveLeft()) return 1; + if (MoveUp() && MoveLineEnd()) return 1; + return 0; +} + +int EBuffer::MoveNext() { + if (CP.Col < LineLen()) + if (MoveRight()) return 1; + if (MoveDown() && MoveLineStart()) return 1; + return 0; +} + + +int EBuffer::MoveWordLeftX(int start) { + if (CP.Col > 0) { + int wS = start, wE = 1 - start; + PELine L = VLine(CP.Row); + int C, P; + + C = CP.Col; + P = CharOffset(L, C); + + if (P > L->Count) P = L->Count; + if (P > 0) { + while ((P > 0) && (WGETBIT(Flags.WordChars, L->Chars[P - 1]) == wE)) P--; + while ((P > 0) && (WGETBIT(Flags.WordChars, L->Chars[P - 1]) == wS)) P--; + C = ScreenPos(L, P); + return SetPos(C, CP.Row); + } else return 0; + } else return 0; +} + + +int EBuffer::MoveWordRightX(int start) { + PELine L = VLine(CP.Row); + int C, P; + int wS = start, wE = 1 - start; + + C = CP.Col; + P = CharOffset(L, C); + + if (P >= L->Count) return 0; + + while ((P < L->Count) && (WGETBIT(Flags.WordChars, L->Chars[P]) == wS)) P++; + while ((P < L->Count) && (WGETBIT(Flags.WordChars, L->Chars[P]) == wE)) P++; + C = ScreenPos(L, P); + return SetPos(C, CP.Row); +} + +int EBuffer::MoveWordLeft() { + return MoveWordLeftX(1); +} + +int EBuffer::MoveWordRight() { + return MoveWordRightX(1); +} + +int EBuffer::MoveWordPrev() { + if (MoveWordLeft()) return 1; + if (MoveUp() && MoveLineEnd()) return 1; + return 0; +} + +int EBuffer::MoveWordNext() { + if (MoveWordRight()) return 1; + if (MoveDown() && MoveLineStart()) return 1; + return 0; +} + +int EBuffer::MoveWordEndLeft() { + return MoveWordLeftX(0); +} + +int EBuffer::MoveWordEndRight() { + return MoveWordRightX(0); +} + +int EBuffer::MoveWordEndPrev() { + if (MoveWordEndLeft()) return 1; + if (MoveUp() && MoveLineEnd()) return 1; + return 0; +} + +int EBuffer::MoveWordEndNext() { + if (MoveWordEndRight()) return 1; + if (MoveDown() && MoveLineStart()) return 1; + return 0; +} + +int EBuffer::MoveWordOrCapLeft() { + if (CP.Col > 0) { + PELine L = VLine(CP.Row); + int C, P; + + C = CP.Col; + P = CharOffset(L, C); + + if (P > L->Count) P = L->Count; + if (P > 0) { + while ((P > 0) && (WGETBIT(Flags.WordChars, L->Chars[P - 1]) == 0)) P--; + while ((P > 0) && (WGETBIT(Flags.WordChars, L->Chars[P - 1]) == 1) && (WGETBIT(Flags.CapitalChars, L->Chars[P - 1]) == 0)) P--; + while ((P > 0) && (WGETBIT(Flags.CapitalChars, L->Chars[P - 1]) == 1)) P--; + C = ScreenPos(L, P); + return SetPos(C, CP.Row); + } else return 0; + } else return 0; +} + +int EBuffer::MoveWordOrCapRight() { + PELine L = VLine(CP.Row); + int C, P; + + C = CP.Col; + P = CharOffset(L, C); + + if (P >= L->Count) return 0; + + while ((P < L->Count) && (WGETBIT(Flags.CapitalChars, L->Chars[P]) == 1)) P++; + while ((P < L->Count) && (WGETBIT(Flags.WordChars, L->Chars[P]) == 1) && (WGETBIT(Flags.CapitalChars, L->Chars[P]) == 0)) P++; + while ((P < L->Count) && (WGETBIT(Flags.WordChars, L->Chars[P]) == 0)) P++; + C = ScreenPos(L, P); + return SetPos(C, CP.Row); +} + +int EBuffer::MoveWordOrCapPrev() { + if (MoveWordOrCapLeft()) return 1; + if (MoveUp() && MoveLineEnd()) return 1; + return 0; +} + +int EBuffer::MoveWordOrCapNext() { + if (MoveWordOrCapRight()) return 1; + if (MoveDown() && MoveLineStart()) return 1; + return 0; +} + +int EBuffer::MoveWordOrCapEndLeft() { + if (CP.Col > 0) { + PELine L = VLine(CP.Row); + int C, P; + + C = CP.Col; + P = CharOffset(L, C); + + if (P > L->Count) P = L->Count; + if (P > 0) { + while ((P > 0) && (WGETBIT(Flags.WordChars, L->Chars[P - 1]) == 1) && (WGETBIT(Flags.CapitalChars, L->Chars[P - 1]) == 0)) P--; + while ((P > 0) && (WGETBIT(Flags.CapitalChars, L->Chars[P - 1]) == 1)) P--; + while ((P > 0) && (WGETBIT(Flags.WordChars, L->Chars[P - 1]) == 0)) P--; + C = ScreenPos(L, P); + return SetPos(C, CP.Row); + } else return 0; + } else return 0; +} + +int EBuffer::MoveWordOrCapEndRight() { + PELine L = VLine(CP.Row); + int C, P; + + C = CP.Col; + P = CharOffset(L, C); + + if (P >= L->Count) return 0; + + while ((P < L->Count) && (WGETBIT(Flags.WordChars, L->Chars[P]) == 0)) P++; + while ((P < L->Count) && (WGETBIT(Flags.CapitalChars, L->Chars[P]) == 1)) P++; + while ((P < L->Count) && (WGETBIT(Flags.WordChars, L->Chars[P]) == 1) && (WGETBIT(Flags.CapitalChars, L->Chars[P]) == 0)) P++; + C = ScreenPos(L, P); + return SetPos(C, CP.Row); +} + +int EBuffer::MoveWordOrCapEndPrev() { + if (MoveWordOrCapEndLeft()) return 1; + if (MoveUp() && MoveLineEnd()) return 1; + return 0; +} + +int EBuffer::MoveWordOrCapEndNext() { + if (MoveWordOrCapEndRight()) return 1; + if (MoveDown() && MoveLineStart()) return 1; + return 0; +} + +int EBuffer::MoveLineStart() { + SetPos(0, CP.Row); + return 1; +} + +int EBuffer::MoveLineEnd() { + SetPos(LineLen(VToR(CP.Row)), CP.Row); + return 1; +} + +int EBuffer::MovePageUp() { + return ScrollDown(GetVPort()->Rows); +} + +int EBuffer::MovePageDown() { + return ScrollUp(GetVPort()->Rows); +} + +int EBuffer::MovePageLeft() { + return ScrollRight(GetVPort()->Cols); +} + +int EBuffer::MovePageRight() { + return ScrollRight(GetVPort()->Cols); +} + +int EBuffer::MovePageStart() { + SetPos(CP.Col, GetVPort()->TP.Row, tmLeft); + return 1; +} + +int EBuffer::MovePageEnd() { + SetNearPos(CP.Col, + GetVPort()->TP.Row + + GetVPort()->Rows - 1, tmLeft); + return 1; +} + +int EBuffer::MoveFileStart() { + SetPos(0, 0); + return 1; +} + +int EBuffer::MoveFileEnd() { + SetPos(LineLen(VToR(VCount - 1)), VCount - 1); + return 1; +} + +int EBuffer::MoveBlockStart() { + if (BB.Col == -1 && BB.Row == -1) + return 0; + assert(BB.Col >= 0 && BB.Row >= 0 && BB.Row < RCount); + if (SetPosR(BB.Col, BB.Row)) + return 1; + return 0; +} + +int EBuffer::MoveBlockEnd() { + if (BE.Col == -1 && BE.Row == -1) + return 0; + assert(BE.Col >= 0 && BE.Row >= 0 && BE.Row < RCount); + if (SetPosR(BE.Col, BE.Row)) + return 1; + return 0; +} + +int EBuffer::MoveFirstNonWhite() { + int C = 0, P = 0; + PELine L = VLine(CP.Row); + + while (C < L->Count) { + if (L->Chars[C] == ' ') P++; + else if (L->Chars[C] == 9) P = NextTab(P, BFI(this, BFI_TabSize)); + else break; + C++; + } + if (SetPos(P, CP.Row) == 0) return 0; + return 1; +} + +int EBuffer::MoveLastNonWhite() { + int C = LineLen(), P; + PELine L = VLine(CP.Row); + + while (C > 0) { + if (L->Chars[C - 1] == ' ' || L->Chars[C - 1] == 9) C--; + else break; + } + P = ScreenPos(VLine(CP.Row), C); + if (SetPos(P, CP.Row) == 0) return 0; + return 1; +} + +int EBuffer::MovePrevEqualIndent() { + int L = VToR(CP.Row); + int I = LineIndented(L); + + while (--L >= 0) + if ((RLine(L)->Count > 0) && (LineIndented(L) == I)) + return SetPosR(I, L); + return 0; +} + +int EBuffer::MoveNextEqualIndent() { + int L = VToR(CP.Row); + int I = LineIndented(L); + + while (L++ < RCount - 1) + if ((RLine(L)->Count > 0) && (LineIndented(L) == I)) + return SetPosR(I, L); + return 0; +} + +int EBuffer::MoveNextTab() { + int P = CP.Col; + + P = NextTab(P, BFI(this, BFI_TabSize)); + return SetPos(P, CP.Row); +} + +int EBuffer::MovePrevTab() { + int P = CP.Col; + + if (P > 0) { + P = ((P - 1) / BFI(this, BFI_TabSize)) * BFI(this, BFI_TabSize); + return SetPos(P, CP.Row); + } else return 0; +} + +int EBuffer::MoveLineTop() { + if (View) + if (GetVPort()->SetTop(GetVPort()->TP.Col, CP.Row) == 0) return 0; + return 1; +} + +int EBuffer::MoveLineCenter() { + if (View) { + int Row = CP.Row - GetVPort()->Rows / 2; + + if (Row < 0) Row = 0; + if (GetVPort()->SetTop(GetVPort()->TP.Col, Row) == 0) return 0; + } + return 1; +} + +int EBuffer::MoveLineBottom() { + if (View) { + int Row = CP.Row - GetVPort()->Rows + 1; + + if (Row < 0) Row = 0; + if (GetVPort()->SetTop(GetVPort()->TP.Col, Row) == 0) return 0; + } + return 1; +} + +int EBuffer::MovePrevPos() { + if (PrevPos.Col == -1 || PrevPos.Row == -1) return 0; + if (SetPosR(PrevPos.Col, PrevPos.Row) == 0) return 0; + return 1; +} + +int EBuffer::MoveSavedPosCol() { + if (SavedPos.Col == -1) return 0; + if (SetPos(SavedPos.Col, CP.Row) == 0) return 0; + return 1; +} + +int EBuffer::MoveSavedPosRow() { + if (SavedPos.Row == -1) return 0; + if (SetPosR(CP.Col, SavedPos.Row) == 0) return 0; + return 1; +} + +int EBuffer::MoveSavedPos() { + if (SavedPos.Col == -1 || SavedPos.Row == -1) return 0; + if (SetPosR(SavedPos.Col, SavedPos.Row) == 0) return 0; + return 1; +} + +int EBuffer::SavePos() { + SavedPos = CP; + SavedPos.Row = VToR(CP.Row); + return 1; +} + +int EBuffer::MoveTabStart() { + PELine X = VLine(CP.Row); + int C = CharOffset(X, CP.Col); + + if (C < X->Count) + if (X->Chars[C] == 9) + return SetPos(ScreenPos(X, C), CP.Row); + return 1; +} + +int EBuffer::MoveTabEnd() { + PELine X = VLine(CP.Row); + int C = CharOffset(X, CP.Col); + + if (C < X->Count) + if (X->Chars[C] == 9) + if (ScreenPos(X, C) < CP.Col) + return SetPos(ScreenPos(X, C + 1), CP.Row); + return 1; +} + +int EBuffer::ScrollLeft(int Cols) { + int C = GetVPort()->TP.Col; + if (SetNearPos(CP.Col + Cols, CP.Row, tmLeft) == 0) return 0; + if (GetVPort()->SetTop(C + Cols, GetVPort()->TP.Row) == 0) return 0; + return 1; +} + +int EBuffer::ScrollRight(int Cols) { + int C = GetVPort()->TP.Col; + if (SetNearPos(CP.Col - Cols, CP.Row, tmLeft) == 0) return 0; + if (GetVPort()->SetTop(C - Cols, GetVPort()->TP.Row) == 0) return 0; + return 1; +} + +int EBuffer::ScrollDown(int Lines) { + int L = GetVPort()->TP.Row; + if (SetNearPos(CP.Col, CP.Row - Lines, tmLeft) == 0) return 0; + if (GetVPort()->SetTop(GetVPort()->TP.Col, L - Lines) == 0) return 0; + return 1; +} + +int EBuffer::ScrollUp(int Lines) { + int L = GetVPort()->TP.Row; + if (SetNearPos(CP.Col, CP.Row + Lines, tmLeft) == 0) return 0; + if (GetVPort()->SetTop(GetVPort()->TP.Col, L + Lines) == 0) return 0; + return 1; +} + +int EBuffer::MoveBeginOrNonWhite() { + if (CP.Col == 0) + return MoveFirstNonWhite(); + else + return MoveLineStart(); +} + +int EBuffer::MoveBeginLinePageFile() { + int L = GetVPort()->TP.Row; + + if (CP.Col == 0 && CP.Row == L) + return MoveFileStart(); + else if (CP.Col == 0) + return MovePageStart(); + else + return MoveLineStart(); +} + +int EBuffer::MoveEndLinePageFile() { + int L = GetVPort()->TP.Row + GetVPort()->Rows - 1; + int Len = LineLen(); + + if (CP.Col == Len && CP.Row == L) + return MoveFileEnd(); + else if (CP.Col == Len) + if (MovePageEnd() == 0) + return 0; + return MoveLineEnd(); +} + +int EBuffer::KillLine() { + int Y = VToR(CP.Row); + + if (Y == RCount - 1) { + if (DelText(Y, 0, LineLen())) return 1; + } else + if (DelLine(Y)) return 1; + return 0; +} + +int EBuffer::KillChar() { + int Y = VToR(CP.Row); + if (CP.Col < LineLen()) { + if (DelText(Y, CP.Col, 1)) return 1; + } else if (LineJoin()) return 1; + return 0; +} + +int EBuffer::KillCharPrev() { + if (CP.Col == 0) { + if (CP.Row > 0) + if (ExposeRow(VToR(CP.Row) - 1) == 0) return 0; + if (!MoveUp()) return 0; + if (!MoveLineEnd()) return 0; + if (LineJoin()) return 1; + } else { + if (!MovePrev()) return 0; + if (DelText(CP.Row, CP.Col, 1)) return 1; + } + return 0; +} + +int EBuffer::KillWord() { + int Y = VToR(CP.Row); + if (CP.Col >= LineLen()) { + if (KillChar() == 0) return 0; + } else { + PELine L = RLine(Y); + int P = CharOffset(L, CP.Col); + int C; + int Class = ChClassK(L->Chars[P]); + + while ((P < L->Count) && (ChClassK(L->Chars[P]) == Class)) P++; + C = ScreenPos(L, P); + if (DelText(Y, CP.Col, C - CP.Col) == 0) return 0; + } + return 1; +} + +int EBuffer::KillWordPrev() { + int Y = VToR(CP.Row); + + if (CP.Col == 0) { + if (KillCharPrev() == 0) return 0; + } else if (CP.Col > LineLen()) { + if (SetPos(LineLen(), CP.Row) == 0) return 0; + } else { + PELine L = RLine(Y); + int P = CharOffset(L, CP.Col); + int C; + int Class = ChClassK(L->Chars[P - 1]); + + while ((P > 0) && (ChClassK(L->Chars[P - 1]) == Class)) P--; + C = ScreenPos(L, P); + if (DelText(Y, C, CP.Col - C) == 0) return 0; + if (SetPos(C, CP.Row) == 0) return 0; + } + return 1; +} + +int EBuffer::KillWordOrCap() { + int Y = VToR(CP.Row); + if (CP.Col >= LineLen()) { + if (KillChar() == 0) return 0; + } else { + PELine L = VLine(CP.Row); + int P = CharOffset(L, CP.Col); + int C; + int Class = ChClassK(L->Chars[P]); + + if (Class == 1) { + if (WGETBIT(Flags.CapitalChars, L->Chars[P]) == 1) + while ((P < L->Count) && (WGETBIT(Flags.CapitalChars, L->Chars[P]) == 1)) P++; + while ((P < L->Count) && (WGETBIT(Flags.WordChars, L->Chars[P]) == 1) && (WGETBIT(Flags.CapitalChars, L->Chars[P]) == 0)) P++; + } else while ((P < L->Count) && (ChClassK(L->Chars[P]) == Class)) P++; + C = ScreenPos(L, P); + if (DelText(Y, CP.Col, C - CP.Col) == 0) return 0; + } + return 1; +} + +int EBuffer::KillWordOrCapPrev() { + int Y = VToR(CP.Row); + + if (CP.Col == 0) { + if (KillCharPrev() == 0) return 0; + } else if (CP.Col > LineLen()) { + if (SetPos(LineLen(), CP.Row) == 0) return 0; + } else { + PELine L = RLine(Y); + int P = CharOffset(L, CP.Col); + int C; + int Class = ChClassK(L->Chars[P - 1]); + + if (Class == 1) { + if (WGETBIT(Flags.CapitalChars, L->Chars[P - 1]) == 0) + while ((P > 0) && (WGETBIT(Flags.WordChars, L->Chars[P - 1]) == 1) && (WGETBIT(Flags.CapitalChars, L->Chars[P - 1]) == 0)) P--; + while ((P > 0) && (WGETBIT(Flags.CapitalChars, L->Chars[P - 1]) == 1)) P--; + } else while ((P > 0) && (ChClassK(L->Chars[P - 1]) == Class)) P--; + C = ScreenPos(L, P); + if (DelText(Y, C, CP.Col - C) == 0) return 0; + if (SetPos(C, CP.Row) == 0) return 0; + } + return 1; +} + +int EBuffer::KillToLineStart() { + int Y = VToR(CP.Row); + if (DelText(Y, 0, CP.Col) == 0) return 0; + if (MoveLineStart() == 0) return 0; + return 1; +} + +int EBuffer::KillToLineEnd() { + int Y = VToR(CP.Row); + if (DelText(Y, CP.Col, LineLen() - CP.Col)) return 1; + return 0; +} + +int EBuffer::KillBlock() { + return BlockKill(); +} + +int EBuffer::KillBlockOrChar() { + if (CheckBlock() == 0) + return KillChar(); + else + return BlockKill(); +} + +int EBuffer::KillBlockOrCharPrev() { + if (CheckBlock() == 0) + return KillCharPrev(); + else + return BlockKill(); +} + +int EBuffer::BackSpace() { + int Y = VToR(CP.Row); + + if (CheckBlock() == 1 && BFI(this, BFI_BackSpKillBlock)) { + if (BlockKill() == 0) + return 0; + } else if (BFI(this, BFI_WordWrap) == 2 && CP.Row > 0 && !IsLineBlank(Y - 1) && + CP.Col <= BFI(this, BFI_LeftMargin) && CP.Col <= LineIndented(Y)) + { + if (SetPos(LineLen(Y - 1), CP.Row - 1) == 0) return 0; + } else if (CP.Col == 0) { + if (CP.Row > 0) + if (ExposeRow(VToR(CP.Row) - 1) == 0) return 0; + if (MoveUp() == 0) return 0; + if (MoveLineEnd() == 0) return 0; + if (LineJoin() == 0) return 0; + } else { + if (BFI(this, BFI_BackSpUnindents) && (LineIndented(Y) >= CP.Col)) { + int C = CP.Col, C1 = 0; + int L = VToR(CP.Row); + + C1 = C; + while (L > 0 && (IsLineBlank(L - 1) || (C1 = LineIndented(L - 1)) >= C)) L--; + if (L == 0) C1 = 0; + if (C1 == C) C1--; + if (C1 < 0) C1 = 0; + if (C1 > C) C1 = C; + if (SetPos(C1, CP.Row) == 0) return 0; + if (C > LineIndented(Y)) return 0; + if (DelText(Y, C1, C - C1) == 0) return 0; + } else if (BFI(this, BFI_BackSpKillTab)) { + int P; + int C = CP.Col, C1; + + P = CharOffset(RLine(Y), C - 1); + C1 = ScreenPos(RLine(Y), P); + if (SetPos(C1, CP.Row) == 0) return 0; + if (DelText(Y, C1, C - C1) == 0) return 0; + } else { + if (MovePrev() == 0) return 0; + if (DelText(Y, CP.Col, 1) == 0) return 0; + } + } +#ifdef CONFIG_WORDWRAP + if (BFI(this, BFI_WordWrap) == 2) { + if (DoWrap(0) == 0) return 0; + } +#endif + if (BFI(this, BFI_Trim)) { + Y = VToR(CP.Row); + if (TrimLine(Y) == 0) return 0; + } + return 1; +} + +int EBuffer::Delete() { + int Y = VToR(CP.Row); + if (CheckBlock() == 1 && BFI(this, BFI_DeleteKillBlock)) { + if (BlockKill() == 0) + return 0; + } else if (CP.Col < LineLen()) { + if (BFI(this, BFI_DeleteKillTab)) { + int P; + int C = CP.Col, C1; + + P = CharOffset(RLine(Y), C); + C1 = ScreenPos(RLine(Y), P + 1); + if (DelText(Y, C, C1 - C) == 0) return 0; + } else + if (DelText(Y, CP.Col, 1) == 0) return 0; + } else + if (LineJoin() == 0) return 0; +#ifdef CONFIG_WORDWRAP + if (BFI(this, BFI_WordWrap) == 2) { + if (DoWrap(0) == 0) return 0; + if (CP.Col >= LineLen(Y)) + if (CP.Row < VCount - 1) { + if (SetPos(BFI(this, BFI_LeftMargin), CP.Row + 1) == 0) return 0; + } + } +#endif + if (BFI(this, BFI_Trim)) + if (TrimLine(VToR(CP.Row)) == 0) + return 0; + return 1; +} + +int EBuffer::LineInsert() { + if (InsLine(VToR(CP.Row), 0)) return 1; + return 0; +} + +int EBuffer::LineAdd() { + if (InsLine(VToR(CP.Row), 1) && MoveDown()) return 1; + return 0; +} + +int EBuffer::LineSplit() { + if (SplitLine(VToR(CP.Row), CP.Col) == 0) return 0; + if (BFI(this, BFI_Trim)) + if (TrimLine(VToR(CP.Row)) == 0) return 0; + return 1; +} + +int EBuffer::LineJoin() { + if (JoinLine(VToR(CP.Row), CP.Col)) return 1; + return 0; +} + +int EBuffer::LineNew() { + if (SplitLine(VToR(CP.Row), CP.Col) == 0) + return 0; + + if (!MoveDown()) + return 0; + + if (CP.Col > 0) { + + if (!MoveLineStart()) + return 0; + + //int Indent = LineIndented(VToR(CP.Row)); + + if (!LineIndent()) + return 0; + + //if (Indent > 0) + // if (InsText(Row, C, Indent, 0) == 0) + // return 0; + + if (BFI(this, BFI_Trim)) + if (TrimLine(VToR(CP.Row - 1)) == 0) + return 0; + } + return 1; +} + +int EBuffer::LineIndent() { + int rc = 1; + + if (BFI(this, BFI_AutoIndent)) { + int L = VToR(CP.Row); + + switch (BFI(this, BFI_IndentMode)) { +#ifdef CONFIG_INDENT_C + case INDENT_C: rc = Indent_C(this, L, 1); break; +#endif +#ifdef CONFIG_INDENT_REXX + case INDENT_REXX: rc = Indent_REXX(this, L, 1); break; +#endif +#ifdef CONFIG_INDENT_SIMPLE + case INDENT_SIMPLE: rc = Indent_SIMPLE(this, L, 1); break; +#endif + default: rc = Indent_Plain(this, L, 1); break; + } + } + if (rc == 0) return 0; + if (BFI(this, BFI_Trim)) + if (TrimLine(VToR(CP.Row)) == 0) return 0; + return 1; +} + +int EBuffer::LineLen() { + return LineLen(VToR(CP.Row)); +} + +int EBuffer::LineCount() { + assert(1 == 0); + return RCount; +} + +int EBuffer::CLine() { + assert(1 == 0); + return VToR(CP.Row); +} + +int EBuffer::CColumn() { + return CP.Col; +} + +int EBuffer::InsertChar(char aCh) { + return InsertString(&aCh, 1); +} + +int EBuffer::TypeChar(char aCh) { // does abbrev expansion if appropriate + if (BFI(this, BFI_InsertKillBlock) == 1) + if (CheckBlock() == 1) + if (BlockKill() == 0) + return 0; +#ifdef CONFIG_ABBREV //fprintf(stderr, "TypeChar\n"); + if (ChClass(aCh) == 0 && BFI(this, BFI_Abbreviations) == 1) { + PELine L = VLine(CP.Row); + int C, P, P1, C1, Len, R; + char Str[256]; + EAbbrev *ab; + + R = VToR(CP.Row); + C = CP.Col; + P = CharOffset(L, C); + if (P >= 0 && P <= L->Count) { + //fprintf(stderr, "TypeChar 1\n"); + P1 = P; + C1 = ScreenPos(L, P); + while ((P > 0) && ((ChClass(L->Chars[P - 1]) == 1) || (L->Chars[P - 1] == '_'))) P--; + Len = P1 - P; + C = ScreenPos(L, P); + assert(C1 - C == Len); + if (Len > 0 && Len < int (sizeof(Str))) { + //fprintf(stderr, "TypeChar 2\n"); + memcpy(Str, L->Chars + P, Len); + Str[Len] = 0; + ab = Mode->FindAbbrev(Str); + if (ab) { + //fprintf(stderr, "TypeChar 3\n"); + if (ab->Replace != 0) { + //fprintf(stderr, "TypeChar 4\n"); + if (DelText(R, C, C1 - C) == 0) + return 0; + if (ab->Replace) { + //fprintf(stderr, "TypeChar 5 %s <- %s\n", ab->Replace, ab->Match); + Len = strlen(ab->Replace); + if (InsText(R, C, Len, ab->Replace) == 0) + return 0; + if (SetPos(C + Len, CP.Row) == 0) + return 0; + } else { + if (SetPos(C, CP.Row) == 0) + return 0; + } + } else { + if (((EGUI *)gui)->ExecMacro(View->MView->Win, ab->Cmd) == 0) + return 0; + } + } + } + } + } +#endif + return InsertString(&aCh, 1); +} + +int EBuffer::InsertString(char *aStr, int aCount) { + int P; + int C, L; + int Y = VToR(CP.Row); + + if (BFI(this, BFI_InsertKillBlock) == 1) + if (CheckBlock() == 1) + if (BlockKill() == 0) + return 0; + + if (BFI(this, BFI_Insert) == 0) + if (CP.Col < LineLen()) + if (KillChar() == 0) + return 0; + if (InsText(Y, CP.Col, aCount, aStr) == 0) + return 0; + C = CP.Col; + L = VToR(CP.Row); + P = CharOffset(RLine(L), C); + P += aCount; + C = ScreenPos(RLine(L), P); + if (SetPos(C, CP.Row) == 0) + return 0; + if (BFI(this, BFI_Trim)) + if (TrimLine(L) == 0) + return 0; +#ifdef CONFIG_WORDWRAP + if (BFI(this, BFI_WordWrap) == 2) { + if (DoWrap(0) == 0) return 0; + } else if (BFI(this, BFI_WordWrap) == 1) { + int P, C = CP.Col; + PELine LP; + int L; + + if (C > BFI(this, BFI_RightMargin)) { + L = CP.Row; + + C = BFI(this, BFI_RightMargin); + P = CharOffset(LP = RLine(L), C); + while ((C > BFI(this, BFI_LeftMargin)) && + ((LP->Chars[P] != ' ') && + (LP->Chars[P] != 9))) + C = ScreenPos(LP, --P); + + if (P <= BFI(this, BFI_LeftMargin)) { + C = BFI(this, BFI_RightMargin); + } else + C = ScreenPos(LP, P); + if (SplitLine(L, C) == 0) return 0; + IndentLine(L + 1, BFI(this, BFI_LeftMargin)); + if (SetPos(CP.Col - C - 1 + BFI(this, BFI_LeftMargin), CP.Row + 1) == 0) return 0; + } + } +#endif + return 1; +} + +int EBuffer::InsertSpacesToTab(int TSize) { + int P = CP.Col, P1; + + if (BFI(this, BFI_InsertKillBlock) == 1) + if (CheckBlock() == 1) + if (BlockKill() == 0) + return 0; + + if (TSize <= 0) + TSize = BFI(this, BFI_TabSize); + + P1 = NextTab(P, TSize); + if (BFI(this, BFI_Insert) == 0) { + if (CP.Col < LineLen()) + if (DelText(VToR(CP.Row), CP.Col, P1 - P) == 0) return 0; + } + if (InsText(VToR(CP.Row), CP.Col, P1 - P, 0) == 0) return 0; + if (SetPos(P1, CP.Row) == 0) return 0; + return 1; +} + +int EBuffer::InsertTab() { + return (BFI(this, BFI_SpaceTabs)) ? + InsertSpacesToTab(BFI(this, BFI_TabSize)) : InsertChar(9); +} + +int EBuffer::InsertSpace() { + return TypeChar(32); +} + +int EBuffer::LineIndented(int Row) { + int P; + char *PC; + int I; + int Ind = 0; + + if (Row < 0) return 0; + if (Row >= RCount) return 0; + P = RLine(Row)->Count; + PC = RLine(Row)->Chars; + + for (I = 0; I < P; I++) { + if (PC[I] == ' ') Ind++; + else if ((PC[I] == 9) && (BFI(this, BFI_ExpandTabs) == 1)) Ind = NextTab(Ind, BFI(this, BFI_TabSize)); + else break; + } + return Ind; +} + +int EBuffer::IndentLine(int Row, int Indent) { + int I, C; + int Ind = Indent; + + if (Row < 0) return 0; + if (Row >= RCount) return 0; + if (Indent < 0) Indent = 0; + I = LineIndented(Row); + if (Indent != I) { + if (I > 0) + if (DelText(Row, 0, I) == 0) return 0; + if (Indent > 0) { + C = 0; + if (BFI(this, BFI_IndentWithTabs)) { + char ch = 9; + + while (BFI(this, BFI_TabSize) <= Indent) { + if (InsText(Row, C, 1, &ch) == 0) return 0; + Indent -= BFI(this, BFI_TabSize); + C += BFI(this, BFI_TabSize); + } + } + if (Indent > 0) + if (InsText(Row, C, Indent, 0) == 0) return 0; + } + } + return Ind - I; +} + +#ifdef CONFIG_UNDOREDO +int EBuffer::CanUndo() { + if (BFI(this, BFI_Undo) == 0) return 0; + if (US.Num == 0 || US.UndoPtr == 0) return 0; + return 1; +} + +int EBuffer::CanRedo() { + if (BFI(this, BFI_Undo) == 0) return 0; + if (US.Num == 0 || US.UndoPtr == US.Num) return 0; + return 1; +} +#endif + +int EBuffer::IsLineBlank(int Row) { + PELine X = RLine(Row); + int P; + + for (P = 0; P < X->Count; P++) + if (X->Chars[P] != ' ' && X->Chars[P] != 9) + return 0; + return 1; +} + +#ifdef CONFIG_WORDWRAP +#define WFAIL(x) return 0 /*do { puts(#x "\x7"); return -1; } while (0) */ + +int EBuffer::DoWrap(int WrapAll) { + int L, Len, C, P, Ind; + PELine LP; + int Left = BFI(this, BFI_LeftMargin), Right = BFI(this, BFI_RightMargin); + int FirstParaLine; + int NoChange = 0, NoChangeX = 0; + + if (Left >= Right) return 0; + + L = VToR(CP.Row); + + FirstParaLine = 0; + if (L > 0) + if (IsLineBlank(L - 1)) FirstParaLine = L; + + while (L < RCount) { + NoChange = 1; + + if (VToR(CP.Row) != L || L != FirstParaLine) { + if (VToR(CP.Row) == L) + if (CP.Col <= LineIndented(L)) + if (SetPos(Left, CP.Row) == 0) WFAIL(1); + Ind = IndentLine(L, Left); + if (VToR(CP.Row) == L) + if (SetPos((CP.Col + Ind > 0) ? CP.Col + Ind : 0, CP.Row) == 0) WFAIL(2); + NoChange = 0; + } + Len = LineLen(L); + + if (IsLineBlank(L)) break; + + if (Len < Right) { + int firstwordbeg = -1; + int firstwordend = -1; + int X; + PELine lp; + + if (L < RCount - 1) { + IndentLine(L + 1, 0); + if ((ScreenPos(RLine(L + 1), RLine(L + 1)->Count) == 0) || + (RLine(L + 1)->Chars[0] == '>') || (RLine(L + 1)->Chars[0] == '<')) break; + } else + break; + if (L + 1 >= RCount) break; + + lp = RLine(L + 1); + for (X = 0; X < lp->Count; X++) { + if (firstwordbeg == -1 && + ((lp->Chars[X] != ' ') && (lp->Chars[X] != '\t'))) + { + firstwordbeg = X; + } else if (firstwordend == -1 && + ((lp->Chars[X] == ' ' || lp->Chars[X] == '\t'))) + { + firstwordend = X - 1; + } + } + if (firstwordbeg != -1) + if (firstwordend == -1) + firstwordend = lp->Count; + + if (firstwordend == -1) break; + if (Right - Len > firstwordend - firstwordbeg) { + if (JoinLine(L, Len + 1) == 0) WFAIL(3); + NoChange = 0; + continue; + } else + IndentLine(L + 1, Left); + } else if (Len > Right) { + C = Right; + P = CharOffset(LP = RLine(L), C); + while ((C > Left) && + ((LP->Chars[P] != ' ') && + (LP->Chars[P] != 9))) + C = ScreenPos(LP, --P); + + if (P <= Left) { + L++; + continue; + } + C = ScreenPos(LP, P); + if (SplitLine(L, C) == 0) WFAIL(4); + IndentLine(L + 1, Left); + if (L < RCount - 2 && LineLen(L + 1) == Left) { + if (!IsLineBlank(L + 2)) { + if (JoinLine(L + 1, Left) == 0) WFAIL(5); + } + } + if (L == VToR(CP.Row) && CP.Col > C) { + if (SetPos(Left + CP.Col - C - 1, CP.Row + 1) == 0) WFAIL(6); + } + NoChange = 0; + L++; + continue; + } + if (WrapAll == 0) + if (NoChangeX) { + //printf("\n\nBreak OUT = %d\n\x7", L); + break; + } + L++; + NoChangeX = NoChange; + } + if (WrapAll == 1) + if (SetPosR(Left, + (L < RCount - 2) ? (L + 2) : + (L < RCount - 1) ? (L + 1) : + (RCount - 1)) == 0) WFAIL(7); + return 1; +} + +int EBuffer::WrapPara() { + while (VToR(CP.Row) < RCount - 1 && IsLineBlank(VToR(CP.Row))) + if (SetPos(CP.Col, CP.Row + 1) == 0) return 0; + return DoWrap(1); +} +#endif + +int EBuffer::LineCenter() { + if (LineTrim() == 0) + return 0; + int ind = LineIndented(VToR(CP.Row)); + int left = BFI(this, BFI_LeftMargin); + int right = BFI(this, BFI_RightMargin); + int len = LineLen(); + + //int chs = len - ind; + int newind = left + ((right - left) - (len - ind)) / 2; + if (newind < left) + newind = left; + return IndentLine(VToR(CP.Row), newind); +} + +int EBuffer::InsPrevLineChar() { + int L = VToR(CP.Row); + int C = CP.Col, P; + + if (L > 0) { + L--; + if (C < LineLen(L)) { + P = CharOffset(RLine(L), C); + return InsertChar(RLine(L)->Chars[P]); + } + } + return 0; +} + +int EBuffer::InsPrevLineToEol() { + int L = VToR(CP.Row); + int C = CP.Col, P; + int Len; + + if (L > 0) { + L--; + P = CharOffset(RLine(L), C); + Len = RLine(L)->Count - P; + if (Len > 0) + return InsertString(RLine(L)->Chars + P, Len); + } + return 0; +} + +int EBuffer::LineDuplicate() { + int Y = VToR(CP.Row); + if (InsLine(Y, 1) == 0) return 0; + if (InsChars(Y + 1, 0, RLine(Y)->Count, RLine(Y)->Chars) == 0) return 0; + return 1; +} + +int EBuffer::TrimLine(int Row) { + PELine L = RLine(Row); + int P, X, E; + + if (L->Count == 0) return 1; + P = L->Count; + while ((P > 0) && ((L->Chars[P - 1] == ' ') || (L->Chars[P - 1] == 9))) + P--; + X = ScreenPos(L, P); + E = ScreenPos(L, L->Count); + if (E - X > 0) + if (DelText(Row, X, E - X, 1) == 0) return 0; + return 1; +} + +int EBuffer::LineTrim() { + return TrimLine(VToR(CP.Row)); +} + +int EBuffer::FileTrim() { + for (int L = 0; L < RCount; L++) + if (TrimLine(L) == 0) + return 0; + return 1; +} + +int EBuffer::BlockTrim() { + EPoint B, E; + int L; + + AutoExtend = 0; + if (CheckBlock() == 0) return 0; + if (RCount <= 0) return 0; + B = BB; + E = BE; + Draw(B.Row, E.Row); + for (L = B.Row; L <= E.Row; L++) { + switch (BlockMode) { + case bmStream: + if (L < E.Row || E.Col != 0) + if (TrimLine(L) == 0) + return 0; + break; + case bmLine: + case bmColumn: + if (L < E.Row) + if (TrimLine(L) == 0) + return 0; + break; + } + } + return 1; +} + +#define TOGGLE(x) \ + Flags.num[BFI_##x] = (Flags.num[BFI_##x]) ? 0 : 1; \ + /*Msg(INFO, #x " is now %s.", Flags.num[BFI_##x] ? "ON" : "OFF");*/ \ + return 1; + +#define TOGGLE_R(x) \ + Flags.num[BFI_##x] = (Flags.num[BFI_##x]) ? 0 : 1; \ + /*Msg(INFO, #x " is now %s.", Flags.num[BFI_##x] ? "ON" : "OFF");*/ \ + FullRedraw(); \ + return 1; + + +int EBuffer::ToggleAutoIndent() { TOGGLE(AutoIndent); } +int EBuffer::ToggleInsert() { TOGGLE(Insert); } +int EBuffer::ToggleExpandTabs() { TOGGLE_R(ExpandTabs); } +int EBuffer::ToggleShowTabs() { TOGGLE_R(ShowTabs); } +int EBuffer::ToggleUndo() { FreeUndo(); TOGGLE(Undo); } +int EBuffer::ToggleReadOnly() { TOGGLE(ReadOnly); } +int EBuffer::ToggleKeepBackups() { TOGGLE(KeepBackups); } +int EBuffer::ToggleMatchCase() { TOGGLE(MatchCase); } +int EBuffer::ToggleBackSpKillTab() { TOGGLE(BackSpKillTab); } +int EBuffer::ToggleDeleteKillTab() { TOGGLE(DeleteKillTab); } +int EBuffer::ToggleSpaceTabs() { TOGGLE(SpaceTabs); } +int EBuffer::ToggleIndentWithTabs() { TOGGLE(IndentWithTabs); } +int EBuffer::ToggleBackSpUnindents() { TOGGLE(BackSpUnindents); } +int EBuffer::ToggleTrim() { TOGGLE(Trim); } +int EBuffer::ToggleShowMarkers() { TOGGLE_R(ShowMarkers); } + +int EBuffer::ToggleWordWrap() { + BFI(this, BFI_WordWrap) = (BFI(this, BFI_WordWrap) + 1) % 3; + /*Msg(INFO, + "WordWrap is now %s.", + (BFI(this, BFI_WordWrap) == 2) ? "AUTO" : + (BFI(this, BFI_WordWrap) == 1) ? "ON" : "OFF"); */ + return 1; +} + +int EBuffer::SetLeftMargin() { + BFI(this, BFI_LeftMargin) = CP.Col; + Msg(S_INFO, "LeftMargin set to %d.", BFI(this, BFI_LeftMargin) + 1); + return 1; +} + +int EBuffer::SetRightMargin() { + BFI(this, BFI_RightMargin) = CP.Col; + Msg(S_INFO, "RightMargin set to %d.", BFI(this, BFI_RightMargin) + 1); + return 1; +} + +int EBuffer::ChangeMode(char *AMode) { + if (FindMode(AMode) != 0) { + Mode = FindMode(AMode); + Flags = Mode->Flags; + HilitProc = 0; + if (Mode && Mode->fColorize) + HilitProc = GetHilitProc(Mode->fColorize->SyntaxParser); + FullRedraw(); + return 1; + } + Msg(S_ERROR, "Mode '%s' not found.", AMode); + return 0; +} + +int EBuffer::ChangeKeys(char *AMode) { + if (FindMode(AMode) != 0) { + Mode = FindMode(AMode); + HilitProc = 0; + if (Mode && Mode->fColorize) + HilitProc = GetHilitProc(Mode->fColorize->SyntaxParser); + FullRedraw(); + return 1; + } + Msg(S_ERROR, "Mode '%s' not found.", AMode); + return 0; +} + +int EBuffer::ChangeFlags(char *AMode) { + if (FindMode(AMode) != 0) { + EMode *XMode; + XMode = FindMode(AMode); + Flags = XMode->Flags; + HilitProc = 0; + if (Mode && Mode->fColorize) + HilitProc = GetHilitProc(Mode->fColorize->SyntaxParser); + FullRedraw(); + return 1; + } + Msg(S_ERROR, "Mode '%s' not found.", AMode); + return 0; +} + diff --git a/src/e_djgpp2.cpp b/src/e_djgpp2.cpp new file mode 100644 index 0000000..8ae57f6 --- /dev/null +++ b/src/e_djgpp2.cpp @@ -0,0 +1,18 @@ +/* e_djgpp2.cpp + * + * Copyright (c) 1997, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + * Contributed by Markus F.X.J. Oberhumer + */ + +// djgpp2 specific routines + +#include "fte.h" + +int EView::SysShowHelp(ExState &State, const char *word) { + Msg(S_ERROR, "Not yet implemented"); + return 0; +} diff --git a/src/e_file.cpp b/src/e_file.cpp new file mode 100644 index 0000000..d35a8f9 --- /dev/null +++ b/src/e_file.cpp @@ -0,0 +1,102 @@ +/* e_file.cpp + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#include "fte.h" + +EBuffer *FindFile(char *FileName) { + EModel *M; + EBuffer *B; + + M = ActiveModel; + while (M) { + if (M->GetContext() == CONTEXT_FILE) { + B = (EBuffer *)M; + if (filecmp(B->FileName, FileName) == 0) { return B; } + } + M = M->Next; + if (M == ActiveModel) break; + } + return 0; +} + +#if 0 +static void SwitchModel(EModel *AModel) { + if (AModel != AcgiveModel && MM && AModel) { + AModel->Prev->Next = AModel->Next; + AModel->Next->Prev = AModel->Prev; + + AModel->Next = MM; + AModel->Prev = MM->Prev; + AModel->Prev->Next = AModel; + MM->Prev = AModel; + MM = AModel; + } +} +#endif + +int FileLoad(int createFlags, const char *FileName, const char *Mode, EView *View) { + char Name[MAXPATH]; + EBuffer *B; + + assert(View != 0); + + if (ExpandPath(FileName, Name) == -1) { + View->MView->Win->Choice(GPC_ERROR, "Error", 1, "O&K", "Invalid path: %s.", FileName); + return 0; + } + B = FindFile(Name); + if (B) { + if (Mode != 0) + B->SetFileName(Name, Mode); + View->SwitchToModel(B); + return 1; + } + B = new EBuffer(createFlags, &ActiveModel, Name); + B->SetFileName(Name, Mode); + + View->SwitchToModel(B); + return 1; +} + +int MultiFileLoad(int createFlags, const char *FileName, const char *Mode, EView *View) { + char fX[MAXPATH]; + int count = 0; + char FPath[MAXPATH]; + char FName[MAXPATH]; + FileFind *ff; + FileInfo *fi; + int rc; + + assert(View != 0); + + JustDirectory(FileName, fX); + if (fX[0] == 0) strcpy(fX, "."); + JustFileName(FileName, FName); + if (ExpandPath(fX, FPath) == -1) return 0; + Slash(FPath, 1); + + ff = new FileFind(FPath, FName, ffHIDDEN | ffFULLPATH); + if (ff == 0) + return 0; + rc = ff->FindFirst(&fi); + while (rc == 0) { + count++; + if (FileLoad(createFlags, fi->Name(), Mode, View) == 0) { + delete fi; + delete ff; + return 0; + } + delete fi; + rc = ff->FindNext(&fi); + } + delete ff; + if (count == 0) + return FileLoad(createFlags, FileName, Mode, View); + return 1; +} diff --git a/src/e_fold.cpp b/src/e_fold.cpp new file mode 100644 index 0000000..1973296 --- /dev/null +++ b/src/e_fold.cpp @@ -0,0 +1,531 @@ +/* e_fold.cpp + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#include "fte.h" + +int EBuffer::FindFold(int Line) { // optimize /*FOLD00*/ + int f = FindNearFold(Line); + if (f != -1) + if (FF[f].line == Line) + return f; + return -1; +} + +int EBuffer::FindNearFold(int Line) { /*FOLD00*/ + int b = 0, B = FCount - 1, c; + + while (b <= B) { + c = (b + B) / 2; +// printf("%d %d %d %d %d\n", b, B, c, Line, FF[c].line); + if (FF[c].line == Line) + return c; + if (c < FCount - 1) { + if (FF[c].line <= Line && FF[c + 1].line > Line) + return c; + } else { + if (FF[c].line <= Line) + return c; + } + if (FF[c].line < Line) + b = c + 1; + else + B = c - 1; + if (b > B) + break; + } + return -1; +} + +int EBuffer::ShowRow(int Row) { /*FOLD00*/ + int V = RToVN(Row), GapSize; + +// printf("Showing row %d\n", Row); + + assert(Row >= 0 && Row < RCount); // 0 cannot be hidden + + if (V + Vis(V) == Row) return 1; // already visible + + assert(VCount <= VAllocated); + if (VCount == VAllocated) { + if (AllocVis(VCount ? (VCount * 2) : 1) == 0) return 0; + memmove(VV + VAllocated - (VCount - VGap), + VV + VGap, + sizeof(int) * (VCount - VGap)); + } + if (VGap != V + 1) + if (MoveVGap(V + 1) == 0) return 0; + VV[VGap] = Row - (VGap); + VGap++; + VCount++; + + GapSize = VAllocated - VCount; + if (VGap != V + 2) + if (MoveVGap(V + 2) == 0) return 0; + for (int i = V + 2; i < VCount; i++) + VV[i + GapSize]--; +// Vis(i, Vis(i) - 1); + UpdateVisible(Row, 1); +// if (CP.Row > Row) +// if (SetPos(CP.Col, CP.Row + 1) == 0) return 0; + Draw(Row, -1); + return 1; +} + +int EBuffer::HideRow(int Row) { /*FOLD00*/ + int V = RToV(Row), GapSize; + + assert(Row > 0 && Row < RCount); // 0 cannot be hidden + + if (V == -1) return 1; // already hidden + UpdateVisible(Row, -1); + + if (VGap != V) + if (MoveVGap(V) == 0) return 0; + GapSize = VAllocated - VCount; + VV[VGap + GapSize] = 0; + VCount--; + GapSize++; + if (VAllocated - VAllocated / 2 > VCount) { + memmove(VV + VGap + GapSize - VAllocated / 3, + VV + VGap + GapSize, + sizeof(int) * (VCount - VGap)); + if (AllocVis(VAllocated - VAllocated / 3) == 0) return 0; + } + GapSize = VAllocated - VCount; + if (VGap != V) + if (MoveVGap(V) == 0) return 0; + for (int i = V; i < VCount; i++) + VV[i + GapSize]++; +// Vis(i, Vis(i) + 1); +// if (CP.Row > Row) +// if (SetPos(CP.Col, CP.Row - 1) == 0) return 0; + Draw(Row, -1); + return 1; +} + +int EBuffer::ExposeRow(int Row) { /*FOLD00*/ + int V; + int f, level, oldlevel = 100; + + //DumpFold(); + + assert(Row >= 0 && Row < RCount); // range + + V = RToV(Row); + if (V != -1) return 1; // already exposed + + f = FindNearFold(Row); + assert(f != -1); // if not visible, must be folded + + while (f >= 0) { + level = FF[f].level; + if (level < oldlevel) { + if (FF[f].open == 0) { +// printf("opening fold %d\n", f); + if (FoldOpen(FF[f].line) == 0) return 0; + } + oldlevel = level; + } + f--; + if (level == 0) break; + } + + V = RToV(Row); +// if (V == -1) { +// printf("Expose Row = %d\n", Row); +// DumpFold(); +// } + assert (V != -1); + return 1; +} + +void EBuffer::UpdateVis(EPoint &M, int Row, int Delta) { /*FOLD00*/ + if (Delta < 0) { + if (M.Row > Row) + if (M.Row < Row - Delta) + M.Row = Row; + else + M.Row += Delta; + } else { + if (M.Row >= Row) + M.Row += Delta; + } +} + +void EBuffer::UpdateVisible(int Row, int Delta) { /*FOLD00*/ + EView *w; + + Row = RToV(Row); + UpdateVis(CP, Row, Delta); + w = View; + if (w) do { + UpdateVis(GetViewVPort(w)->TP, Row, Delta); + UpdateVis(GetViewVPort(w)->CP, Row, Delta); + w = w->Next; + } while (w != View); +} + +int EBuffer::FoldCreate(int Line) { /*FOLD00*/ + int n; + + if (Modify() == 0) return 0; + + if (FindFold(Line) != -1) return 1; // already exists + +#ifdef CONFIG_UNDOREDO + if (BFI(this, BFI_Undo)) { + if (PushULong(Line) == 0) return 0; + if (PushUChar(ucFoldCreate) == 0) return 0; + } +#endif + + n = FindNearFold(Line); + n++; + FF = (EFold *) realloc((void *)FF, sizeof(EFold) * ((1 + FCount) | 7)); + assert(FF != 0); + memmove(FF + n + 1, FF + n, sizeof(EFold) * (FCount - n)); + FCount++; + FF[n].line = Line; + FF[n].level = 0; + FF[n].open = 1; + FF[n].flags = 0; + Draw(Line, Line); + return 1; +} + +int EBuffer::FoldCreateByRegexp(char *Regexp) { /*FOLD00*/ + RxNode *R; + int err = 1; + + if (Modify() == 0) return 0; + + R = RxCompile(Regexp); + if (R != NULL) { + PELine X; + int first = -1; + int L; + + for (L = 0; L < RCount; L++) { + RxMatchRes RM; + + X = RLine(L); + if (RxExec(R, X->Chars, X->Count, X->Chars, &RM) == 1) { + if (first >= 0) { + int i; + + for(i = L; i > 0; i--) { + PELine Y; + + Y = RLine(i); + if ((Y->Count == 0) || strrchr(Y->Chars, '}')) { + if ((L - i) > 2) { + while ((i > 0) && (RLine(i - 1)->Count == 0)) + i--; + if ((first >= 0) && i + && (FoldCreate(i) == 0)) + err = 0; + } + break; + } + } + } else + first = L; + if (FoldCreate(L) == 0) { + err = 0; + break; + } + } + } + RxFree(R); + } + return err; +} + +int EBuffer::FoldCreateAtRoutines() { /*FOLD00*/ + if (BFS(this, BFS_RoutineRegexp) == 0) + return 0; + return FoldCreateByRegexp(BFS(this, BFS_RoutineRegexp)); +} + +int EBuffer::FoldDestroy(int Line) { /*FOLD00*/ + int f = FindFold(Line); + + if (Modify() == 0) return 0; + + if (f == -1) return 0; + if (FF[f].open == 0) + if (FoldOpen(Line) == 0) return 0; + +#ifdef CONFIG_UNDOREDO + if (BFI(this, BFI_Undo)) { + if (PushULong(FF[f].level) == 0) return 0; + if (PushULong(Line) == 0) return 0; + if (PushUChar(ucFoldDestroy) == 0) return 0; + } +#endif + + memmove(FF + f, FF + f + 1, sizeof(EFold) * (FCount - f - 1)); + FCount--; + FF = (EFold *) realloc((void *)FF, sizeof(EFold) * (FCount | 7)); + Draw(Line, Line); + return 1; +} + +int EBuffer::FoldDestroyAll() { /*FOLD00*/ + int l; + + if (Modify() == 0) return 0; + + for (l = 0; l < RCount; l++) + if (FindFold(l) != -1) + if (FoldDestroy(l) == 0) return 0; + return 1; +} + +int EBuffer::FoldPromote(int Line) { /*FOLD00*/ + int f = FindFold(Line); + + if (Modify() == 0) return 0; + + if (f == -1) return 0; + if (FF[f].open == 0) return 0; + if (FF[f].level == 0) return 0; + +#ifdef CONFIG_UNDOREDO + if (BFI(this, BFI_Undo)) { + if (PushULong(Line) == 0) return 0; + if (PushUChar(ucFoldPromote) == 0) return 0; + } +#endif + + if ((FF[f].line > 0) && (ExposeRow(FF[f].line - 1) == 0)) + return 0; + + FF[f].level--; + Draw(Line, Line); + return 1; +} + +int EBuffer::FoldDemote(int Line) { /*FOLD00*/ + int f = FindFold(Line); + + if (Modify() == 0) return 0; + + if (f == -1) return 0; + if (FF[f].open == 0) return 0; + if (FF[f].level == 99) return 0; + +#ifdef CONFIG_UNDOREDO + if (BFI(this, BFI_Undo)) { + if (PushULong(Line) == 0) return 0; + if (PushUChar(ucFoldDemote) == 0) return 0; + } +#endif + if ((FF[f].line > 0) && (ExposeRow(FF[f].line - 1) == 0)) + return 0; + + FF[f].level++; + Draw(Line, Line); + return 1; +} + +int EBuffer::FoldOpen(int Line) { /*FOLD00*/ + int f = FindFold(Line); + int l; + int level, toplevel; + int top; + + if (f == -1) return 0; + if (FF[f].open == 1) return 1; // already open + + if (Modify() == 0) return 0; + +#ifdef CONFIG_UNDOREDO + if (BFI(this, BFI_Undo)) { + if (PushULong(Line) == 0) return 0; + if (PushUChar(ucFoldOpen) == 0) return 0; + } +#endif + + FF[f].open = 1; + top = FF[f].line; + toplevel = FF[f].level; + // printf("Fold starts with %d\n", FF[f].line); + if (ShowRow(FF[f].line) == 0) return 0; + while (f < FCount) { + level = FF[f].level; + if (FF[f].open == 1) { + // fold is open + if (f == FCount - 1) { + for (l = FF[f].line; l < RCount; l++) + if (l != top) + if (ShowRow(l) == 0) return 0; + } else { + for (l = FF[f].line; l < FF[f + 1].line; l++) + if (l != top) + if (ShowRow(l) == 0) return 0; + } + f++; + } else { // fold is closed + // show head line + if (ShowRow(FF[f].line) == 0) return 0; + // skip closed folds + while ((f < FCount) && (level < FF[f + 1].level)) + f++; + f++; + } + if (f < FCount && FF[f].level <= toplevel) + break; + } + return 1; +} + +int EBuffer::FoldOpenAll() { /*FOLD00*/ + int l; + + for (l = 0; l < RCount; l++) + if (FindFold(l) != -1) + if (FoldOpen(l) == 0) return 0; + return 1; +} + +int EBuffer::FoldOpenNested() { /*FOLD00*/ + int Line = VToR(CP.Row); + int f = FindFold(Line); + int l; + int level; + + if (f == -1) return 0; + level = FF[f].level; + + while (f + 1 < FCount && FF[f + 1].level > level) f++; + + if (f + 1 == FCount) { + if (FoldOpen(Line) == 0) return 0; + } else { + for (l = Line; l < RCount && l < FF[f + 1].line; l++) { + if (FindFold(l) != -1) + if (FoldOpen(l) == 0) return 0; + } + } + return 0; +} + +int EBuffer::FoldClose(int Line) { /*FOLD00*/ + int f = FindNearFold(Line); + int l, top; + int level; + + if (f == -1) return 0; + if (FF[f].open == 0) return 1; // already closed + + if (Modify() == 0) return 0; + + if (SetPosR(CP.Col, FF[f].line, tmLeft) == 0) return 0; + +#ifdef CONFIG_UNDOREDO + if (BFI(this, BFI_Undo)) { + if (PushULong(Line) == 0) return 0; + if (PushUChar(ucFoldClose) == 0) return 0; + } +#endif + + FF[f].open = 0; + top = FF[f].line; + level = FF[f].level; + while ((f < FCount - 1) && (FF[f + 1].level > level)) f++; + + /* performance tweak: do it in reverse (we'll see if it helps) */ + + if (f == FCount - 1) { + for (l = RCount - 1; l > top; l--) + if (HideRow(l) == 0) return 0; + } else { + for (l = FF[f + 1].line - 1; l > top; l--) + if (HideRow(l) == 0) return 0; + } + + /* yup, it does. try below for a (MUCH!) slower version */ + + /*if (f == FCount - 1) { + for (l = top + 1; l < RCount; l++) + if (HideRow(l) == 0) return 0; + } else { + for (l = top + 1; l < FF[f + 1].line; l++) + if (HideRow(l) == 0) return 0; + }*/ + return 1; +} + +int EBuffer::FoldCloseAll() { /*FOLD00*/ + int l; + + for (l = RCount - 1; l >= 0; l--) + if (FindFold(l) != -1) + if (FoldClose(l) == 0) return 0; + return 1; +} + +int EBuffer::FoldToggleOpenClose() { /*FOLD00*/ + int Line = VToR(CP.Row); + int f; + + f = FindNearFold(Line); + if (f == -1) + return 0; + if (FF[f].open) { + if (FoldClose(Line) == 0) return 0; + } else { + if (FoldOpen(Line) == 0) return 0; + } + return 1; +} + +int EBuffer::MoveFoldTop() { /*FOLD00*/ + int f = FindNearFold(VToR(CP.Row)); + + if (f == 0 || f == -1) return 0; + + if (FF[f].line == VToR(CP.Row)) + return 1; + if (SetPosR(CP.Col, FF[f].line, tmLeft) == 0) return 0; + return 1; +} + +int EBuffer::MoveFoldPrev() { /*FOLD00*/ + int f = FindNearFold(VToR(CP.Row)); + + if (f == 0 || f == -1) return 0; + + if (FF[f].line == VToR(CP.Row)) { + do { + f--; + if (f < 0) return 0; + if (RToV(FF[f].line) != -1) + break; + } while (1); + } + if (SetPosR(CP.Col, FF[f].line, tmLeft) == 0) return 0; + return 1; +} + +int EBuffer::MoveFoldNext() { /*FOLD00*/ + int f = FindNearFold(VToR(CP.Row)); + + if (f == FCount - 1 || f == -1) return 0; + + do { + f++; + if (f == FCount) return 0; + if (RToV(FF[f].line) != -1) + break; + } while (1); + if (SetPosR(CP.Col, FF[f].line, tmLeft) == 0) return 0; + return 1; +} diff --git a/src/e_line.cpp b/src/e_line.cpp new file mode 100644 index 0000000..b26fa26 --- /dev/null +++ b/src/e_line.cpp @@ -0,0 +1,233 @@ +/* e_line.cpp + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#include "fte.h" + +ELine::ELine(int ACount, char *AChars) { + Chars = NULL; + Count = ACount; + Allocate(Count); +#ifdef CONFIG_SYNTAX_HILIT + StateE = 0; +#endif + if (AChars) + memcpy(Chars, AChars, Count); + else + memset(Chars, ' ', Count); +} + +ELine::ELine(char *AChars, int ACount) { + Chars = AChars; + Count = ACount; +#ifdef CONFIG_SYNTAX_HILIT + StateE = 0; +#endif +} + +ELine::~ELine() { + if (Chars) + free(Chars); +} + +int ELine::Allocate(unsigned int Bytes) { + unsigned int Allocated; + + Allocated = (Bytes | CHAR_TRESHOLD); + if (Chars) + Chars = (char *) realloc(Chars, Allocated); + else + Chars = (char *) malloc(Allocated); + if (Chars == NULL) + return 0; + return 1; +} + +int EBuffer::ScreenPos(ELine *L, int Offset) { + int ExpandTabs = BFI(this, BFI_ExpandTabs); + int TabSize = BFI(this, BFI_TabSize); + + if (!ExpandTabs) { + return Offset; + } else { + char *p = L->Chars; + int Len = L->Count; + int Pos = 0; + int Ofs = Offset; + + if (Ofs > Len) { + while (Len > 0) { + if (*p++ != '\t') + Pos++; + else + Pos = NextTab(Pos, TabSize); + Len--; + } + Pos += Ofs - L->Count; + } else { + while (Ofs > 0) { + if (*p++ != '\t') + Pos++; + else + Pos = NextTab(Pos, TabSize); + Ofs--; + } + } + return Pos; + } +} + +int EBuffer::CharOffset(ELine *L, int ScreenPos) { + int ExpandTabs = BFI(this, BFI_ExpandTabs); + int TabSize = BFI(this, BFI_TabSize); + + if (!ExpandTabs) { + return ScreenPos; + } else { + int Pos = 0; + int Ofs = 0; + char *p = L->Chars; + int Len = L->Count; + + while (Len > 0) { + if (*p++ != '\t') + Pos++; + else + Pos = NextTab(Pos, TabSize); + if (Pos > ScreenPos) + return Ofs; + Ofs++; + Len--; + } + return Ofs + ScreenPos - Pos; + } +} + +int EBuffer::Allocate(int ACount) { + PELine *L; + + L = (PELine *) realloc(LL, sizeof(PELine) * (ACount + 1)); + if (L == 0 && ACount != 0) + return 0; + RAllocated = ACount; + LL = L; + return 1; +} + +int EBuffer::MoveRGap(int RPos) { + int GapSize = RAllocated - RCount; + + if (RGap == RPos) return 1; + if (RPos < 0 || RPos > RCount) return 0; + + if (RGap < RPos) { + if (RPos - RGap == 1) { + LL[RGap] = LL[RGap + GapSize]; + } else { + memmove(LL + RGap, + LL + RGap + GapSize, + sizeof(PELine) * (RPos - RGap)); + } + } else { + if (RGap - RPos == 1) { + LL[RPos + GapSize] = LL[RPos]; + } else { + memmove(LL + RPos + GapSize, + LL + RPos, + sizeof(PELine) * (RGap - RPos)); + } + } + RGap = RPos; + return 1; +} + +int EBuffer::AllocVis(int ACount) { + int *V; + + V = (int *) realloc(VV, sizeof(int) * (ACount + 1)); + if (V == 0 && ACount != 0) return 0; + VAllocated = ACount; + VV = V; + return 1; +} + +int EBuffer::MoveVGap(int VPos) { + int GapSize = VAllocated - VCount; + + if (VGap == VPos) return 1; + if (VPos < 0 || VPos > VCount) return 0; + + if (VGap < VPos) { + if (VPos - VGap == 1) { + VV[VGap] = VV[VGap + GapSize]; + } else { + memmove(VV + VGap, + VV + VGap + GapSize, + sizeof(VV[0]) * (VPos - VGap)); + } + } else { + if (VGap - VPos == 1) { + VV[VPos + GapSize] = VV[VPos]; + } else { + memmove(VV + VPos + GapSize, + VV + VPos, + sizeof(VV[0]) * (VGap - VPos)); + } + } + VGap = VPos; + return 1; +} + +int EBuffer::RToV(int No) { + int L = 0, R = VCount, M, V; + + if (No > Vis(VCount - 1) + VCount - 1) // beyond end + return -1; + if (No < VCount) // no folds before (direct match) + if (Vis(No) == 0) return No; + + while (L < R) { + M = (L + R) >> 1; + V = Vis(M) + M; + if (V == No) + return M; + else if (V > No) + R = M; + else + L = M + 1; + } + return -1; +} + +int EBuffer::RToVN(int No) { + int L = 0, R = VCount, M, V; + + if (No == RCount) + return VCount; + if (No > Vis(VCount - 1) + VCount - 1) + return VCount - 1; + if (No < VCount) + if (Vis(No) == 0) return No; + + while (L < R) { + M = (L + R) >> 1; + V = Vis(M) + M; + if (V == No) + return M; + else if (V > No) + R = M; + else { + if (M == VCount - 1) + return M; + else if (Vis(M + 1) + M + 1 > No) + return M; + L = M + 1; + } + } + return R; +} diff --git a/src/e_loadsave.cpp b/src/e_loadsave.cpp new file mode 100644 index 0000000..7acc85b --- /dev/null +++ b/src/e_loadsave.cpp @@ -0,0 +1,450 @@ +/* e_loadsave.cpp + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#include "fte.h" + +int EBuffer::Load() { + return LoadFrom(FileName); +} + +int EBuffer::Reload() { + int R = VToR(CP.Row), C = CP.Col; + + if (LoadFrom(FileName) == 0) + return 0; + SetNearPosR(C, R); + return 1; +} + +int EBuffer::Save() { + if (BFI(this, BFI_ReadOnly)) { + Msg(S_ERROR, "File is read-only."); + return 0; + } + if (BFI(this, BFI_TrimOnSave)) + FileTrim(); + return SaveTo(FileName); +} + +char FileBuffer[RWBUFSIZE]; + +int EBuffer::LoadFrom(char *AFileName) { + int fd; + int len = 0, partLen; + unsigned long numChars = 0, Lines = 0; + char *p, *e, *m = NULL; + int lm = 0; + int lf; + int SaveUndo, SaveReadOnly; + int first = 1; + int strip = BFI(this, BFI_StripChar); + int lchar = BFI(this, BFI_LineChar); + int margin = BFI(this, BFI_LoadMargin); + + FileOk = 0; + fd = open(AFileName, O_RDONLY | O_BINARY, 0); + if (fd == -1) { + if (errno != ENOENT) { + Msg(S_INFO, "Could not open file %s (errno=%d, %s) .", + AFileName, errno, strerror(errno)); + } else { + Msg(S_INFO, "New file %s.", AFileName); + } + Loaded = 1; + return 0; + } + Loading = 1; + Clear(); + BlockUnmark(); + SaveUndo = BFI(this, BFI_Undo); + SaveReadOnly = BFI(this, BFI_ReadOnly); + BFI(this, BFI_Undo) = 0; + BFI(this, BFI_ReadOnly) = 0; + + while ((len = read(fd, FileBuffer, sizeof(FileBuffer))) > 0) { + if (first) { + first = 0; + if (BFI(this, BFI_DetectLineSep)) { + int was_lf = 0, was_cr = 0; + for (int c = 0; c < len; c++) { + if (FileBuffer[c] == 10) { + was_lf++; + break; + } else if (FileBuffer[c] == 13) { + was_cr++; + if (was_cr == 2) + break; + } + } + /* !!! fails if first line > 32k + * ??? set first to 1 in that case ? */ + if (was_cr || was_lf) { + BFI(this, BFI_StripChar) = -1; + BFI(this, BFI_LoadMargin) = -1; + BFI(this, BFI_AddLF) = 0; + BFI(this, BFI_AddCR) = 0; + if (was_lf) { + BFI(this, BFI_LineChar) = 10; + BFI(this, BFI_AddLF) = 1; + if (was_cr) { + BFI(this, BFI_StripChar) = 13; + BFI(this, BFI_AddCR) = 1; + } + } else if (was_cr) { + BFI(this, BFI_LineChar) = 13; + BFI(this, BFI_AddCR) = 1; + } else { + BFI(this, BFI_LineChar) = -1; + BFI(this, BFI_LoadMargin) = 64; + } + strip = BFI(this, BFI_StripChar); + lchar = BFI(this, BFI_LineChar); + margin = BFI(this, BFI_LoadMargin); + } + } + } + p = FileBuffer; + do { + if (lchar != -1) { // do we have a LINE delimiter + e = (char *)memchr((void *)p, lchar, FileBuffer - p + len); + if (e == NULL) { + e = FileBuffer + len; + lf = 0; + } else + lf = 1; + } else if (margin != -1) { // do we have a right margin for wrap + if (FileBuffer + len >= p + margin) { + e = p + margin; + lf = 1; + } else { + e = FileBuffer + len; + lf = 0; + } + } else { + e = FileBuffer + len; + lf = 0; + } + partLen = e - p; // # of chars in buffer for current line + m = (char *)realloc((void *)m, (lm + partLen) + CHAR_TRESHOLD); + if (m == NULL) + goto fail; + memcpy((void *)(m + lm), p, partLen); + lm += partLen; + numChars += partLen; + + if (lf) { + // there is a new line, add it to buffer + + if (lm == 0 && m == NULL && (m = (char *)malloc(CHAR_TRESHOLD)) == 0) + goto fail; +#if 0 + { // support for VIM tabsize commands + char *t = strstr(m,"vi:ts="); + int ts = 0; + if (t && isdigit(t[6])) + ts = atoi(&t[6]); + if (ts > 0 && ts <= 16) + BFI(this, BFI_TabSize) = ts; + } +#endif + + // Grow the line table if required, + if (RCount == RAllocated) + if (Allocate(RCount ? (RCount * 2) : 1) == 0) + goto fail; + if ((LL[RCount++] = new ELine((char *)m, lm)) == 0) + goto fail; + RGap = RCount; + + lm = 0; + m = NULL; + Lines++; + } + + p = e; + if (lchar != -1) // skip LINE terminator/separator + p++; + } while (lf); + Msg(S_INFO, "Loading: %d lines, %d bytes.", Lines, numChars); + } + + if ((RCount == 0) || (lm > 0) || !BFI(this, BFI_ForceNewLine)) { + if (lm == 0 && m == NULL && (m = (char *)malloc(CHAR_TRESHOLD)) == 0) + goto fail; + // Grow the line table if required, + if (RCount == RAllocated) + if (Allocate(RCount ? (RCount * 2) : 1) == 0) + goto fail; + if ((LL[RCount++] = new ELine(m, lm)) == 0) + goto fail; + m = NULL; + RGap = RCount; + } + + // Next time when you introduce something like this + // check all code paths - as the whole memory management + // is broken - you have forget to clear 'm' two line above comment! + // kabi@users.sf.net + // this bug has caused serious text corruption which is the worst + // thing for text editor + if (m) + free(m); + m = NULL; + + // initialize folding array. + // TODO: allocate only when folds are actually used. + // needs fixing a lot of code in other places. + VCount = RCount; + VGap = VCount; + if (AllocVis(VCount ? VCount : 1) == 0) + goto fail; + memset(VV, 0, VCount * sizeof(int)); + + if (strip != -1) { // strip CR character from EOL if specified + + // TODO: this should be done during load above to improve performance + for (int l = 0; l < RCount; l++) { + if (LL[l]->Count > 0) + if (LL[l]->Chars[LL[l]->Count - 1] == strip) + LL[l]->Count--; + } + } + if ((BFI(this, BFI_SaveFolds) != 0)) { + int len_start = 0, len_end = 0; + int level = 0, open = 0; + int l; + int pos = -1; + char foldnum[3] = "00"; + + if (BFS(this, BFS_CommentStart) == 0) len_start = 0; + else len_start = strlen(BFS(this, BFS_CommentStart)); + if (BFS(this, BFS_CommentEnd) == 0) len_end = 0; + else len_end = strlen(BFS(this, BFS_CommentEnd)); + + for (l = RCount - 1; l >= 0; l--) { + if (LL[l]->Count >= len_start + len_end + 6) { + open = -1; + level = -1; + if (BFI(this, BFI_SaveFolds) == 1) { + pos = 0; + } else if (BFI(this, BFI_SaveFolds) == 2) { + pos = LL[l]->Count - len_start - 6 - len_end; + } + if (((len_start == 0) || + (memcmp(LL[l]->Chars + pos, + BFS(this, BFS_CommentStart), len_start) == 0) + ) && + ((len_end == 0) || + (memcmp(LL[l]->Chars + pos + len_start + 6, + BFS(this, BFS_CommentEnd), len_end) == 0)) + ) + { + if (memcmp(LL[l]->Chars + pos + len_start, + "FOLD",4) == 0) + { + open = 1; + } else if (memcmp(LL[l]->Chars + pos + len_start, + "fold", 4) == 0) { + open = 0; + } else + open = -1; + + foldnum[0] = LL[l]->Chars[pos + len_start + 4]; + foldnum[1] = LL[l]->Chars[pos + len_start + 4 + 1]; + if (1 != sscanf(foldnum, "%2d", &level)) + level = -1; + + if (!isdigit(LL[l]->Chars[pos + len_start + 4]) || + !isdigit(LL[l]->Chars[pos + len_start + 5])) + level = -1; + + if (open != -1 && level != -1 && open < 100) { + int f; + + if (FoldCreate(l) == 0) goto fail; + f = FindFold(l); + assert(f != -1); + FF[f].level = (char)(level & 0xFF); + if (open == 0) + if (FoldClose(l) == 0) goto fail; + memmove(LL[l]->Chars + pos, + LL[l]->Chars + pos + len_start + len_end + 6, + LL[l]->Count - pos - len_start - len_end - 6); + LL[l]->Count -= len_start + len_end + 6; + } + } + } + } + } + if (SetPosR(0, 0) == 0) return 0; + BFI(this, BFI_Undo) = SaveUndo; + BFI(this, BFI_ReadOnly) = SaveReadOnly; + if (stat(FileName, &FileStatus) == -1) { + memset(&FileStatus, 0, sizeof(FileStatus)); + FileOk = 0; + goto fail; + } else { + if (!(FileStatus.st_mode & (S_IWRITE | S_IWGRP | S_IWOTH))) + BFI(this, BFI_ReadOnly) = 1; + else + BFI(this, BFI_ReadOnly) = 0; + } + close(fd); + + FileOk = 1; + Modified = 0; + Loading = 0; + Loaded = 1; + Draw(0, -1); + Msg(S_INFO, "Loaded %s.", AFileName); + return 1; +fail: + BFI(this, BFI_Undo) = SaveUndo; + BFI(this, BFI_ReadOnly) = SaveReadOnly; + close(fd); + Loading = 0; + Draw(0, -1); + View->MView->Win->Choice(GPC_ERROR, "Error", 1, "O&K", "Error loading %s.", AFileName); + return 0; +} + +int EBuffer::SaveTo(char *AFileName) { + char ABackupName[MAXPATH]; + struct stat StatBuf; + + FILE *fp; + int l; + PELine L; + unsigned long ByteCount = 0, OldCount = 0; + + int f; + char fold[64]; + unsigned int foldlen = 0; + + if (FileOk && (stat(FileName, &StatBuf) == 0)) { + if (FileStatus.st_size != StatBuf.st_size || + FileStatus.st_mtime != StatBuf.st_mtime) + { + switch (View->MView->Win->Choice(GPC_ERROR, "File Changed on Disk", + 2, + "&Save", + "&Cancel", + "%s", FileName)) + { + case 0: + break; + case 1: + case -1: + default: + return 0; + } + } + } + + if (RCount <= 0) return 0; + Msg(S_INFO, "Backing up %s...", AFileName); + if (MakeBackup(AFileName, (char *)ABackupName) == 0) { + View->MView->Win->Choice(GPC_ERROR, "Error", 1, "O&K", "Could not create backup file."); + return 0; + } + Msg(S_INFO, "Writing %s...", AFileName); + + fp = 0; +#ifdef OS2 // to preserve EA's ? + fp = fopen(AFileName, "r+b"); + if (fp != 0) +#if defined(__IBMCPP__) || defined(__WATCOMC__) + if ( chsize (fileno(fp), 0) != 0) +#else + if (ftruncate(fileno(fp), 0) != 0) +#endif // __IBMCPP__ || __WATCOMC__ + goto erroropen; +#endif // OS2 + if (fp == 0) + fp = fopen(AFileName, "wb"); + if (fp == 0) goto erroropen; + + setvbuf(fp, FileBuffer, _IOFBF, sizeof(FileBuffer)); + + for (l = 0; l < RCount; l++) { + L = RLine(l); + f = FindFold(l); + + // format fold + if ((f != -1) && (BFI(this, BFI_SaveFolds) != 0)) { + foldlen = 0; + if (BFS(this, BFS_CommentStart) != 0) { + strcpy(fold + foldlen, BFS(this, BFS_CommentStart)); + foldlen += strlen(BFS(this, BFS_CommentStart)); + } + foldlen += sprintf(fold + foldlen, + FF[f].open ? "FOLD%02d" : "fold%02d", + FF[f].level); + if (BFS(this, BFS_CommentEnd) != 0) { + strcpy(fold + foldlen, BFS(this, BFS_CommentEnd)); + foldlen += strlen(BFS(this, BFS_CommentEnd)); + } + ByteCount += foldlen; + } + + // write bol fold + if (f != -1 && BFI(this, BFI_SaveFolds) == 1) + if (fwrite(fold, 1, foldlen, fp) != foldlen) goto fail; + + // write data + if ((int)(fwrite(L->Chars, 1, L->Count, fp)) != L->Count) + goto fail; + ByteCount += L->Count; + + // write eof fold + if (f != -1 && BFI(this, BFI_SaveFolds) == 2) + if (fwrite(fold, 1, foldlen, fp) != foldlen) goto fail; + + // write eol + if ((l < RCount - 1) || BFI(this, BFI_ForceNewLine)) { + if (BFI(this, BFI_AddCR) == 1) { + if (fputc(13, fp) < 0) goto fail; + ByteCount++; + } + if (BFI(this, BFI_AddLF) == 1) { + if (fputc(10, fp) < 0) goto fail; + ByteCount++; + } + } + if (ByteCount > OldCount + 65536) { + Msg(S_INFO, "Saving: %d lines, %d bytes.", l, ByteCount); + OldCount = ByteCount; + } + } + if (fclose(fp) != 0) goto fail; + Modified = 0; + FileOk = 1; + if (stat(FileName, &FileStatus) == -1) { + memset(&FileStatus, 0, sizeof(FileStatus)); + FileOk = 0; + goto fail; + } + Msg(S_INFO, "Wrote %s.", AFileName); + if (BFI(this, BFI_KeepBackups) == 0) { + unlink(ABackupName); + } + return 1; +fail: + fclose(fp); + unlink(AFileName); + if (rename(ABackupName, AFileName) == -1) { + View->MView->Win->Choice(GPC_ERROR, "Error", 1, "O&K", "Error renaming backup file to original!"); + } else { + View->MView->Win->Choice(GPC_ERROR, "Error", 1, "O&K", "Error writing file, backup restored."); + } + return 0; +erroropen: + View->MView->Win->Choice(GPC_ERROR, "Error", 1, "O&K", "Error writing %s (errno=%d).", AFileName, errno); + return 0; +} diff --git a/src/e_mark.cpp b/src/e_mark.cpp new file mode 100644 index 0000000..869b0cd --- /dev/null +++ b/src/e_mark.cpp @@ -0,0 +1,258 @@ +#include "fte.h" + +EMarkIndex markIndex; + +EMark::EMark(char *aName, char *aFileName, EPoint aPoint, EBuffer *aBuffer) { + Name = new char[strlen(aName) + 1]; + FileName = new char[strlen(aFileName) + 1]; + Buffer = 0; + Point = aPoint; + assert(Name != 0); + assert(FileName != 0); + strcpy(Name, aName); + strcpy(FileName, aFileName); + if (aBuffer == 0) + aBuffer = FindFile(aFileName); + if (aBuffer && aBuffer->Loaded) + setBuffer(aBuffer); + else + aBuffer = 0; +} + +EMark::~EMark() { + if (Buffer) + removeBuffer(Buffer); + delete Name; + delete FileName; +} + +int EMark::setBuffer(EBuffer *aBuffer) { + assert(aBuffer != 0); + assert(filecmp(aBuffer->FileName, FileName) == 0); + + if (Point.Row >= aBuffer->RCount) + Point.Row = aBuffer->RCount - 1; + if (Point.Row < 0) + Point.Row = 0; + + if (aBuffer->PlaceBookmark(Name, Point) == 1) { + Buffer = aBuffer; + return 1; + } + return 0; +} + +int EMark::removeBuffer(EBuffer *aBuffer) { + assert(aBuffer != 0); + if (Buffer == 0 || Buffer != aBuffer) + return 0; + assert(filecmp(aBuffer->FileName, FileName) == 0); + + if (Buffer->GetBookmark(Name, Point) == 0) + return 0; + if (Buffer->RemoveBookmark(Name) == 0) + return 0; + + Buffer = 0; + return 1; +} + +EPoint &EMark::getPoint() { + if (Buffer) { + assert(Buffer->GetBookmark(Name, Point) != 0); + } + return Point; +} + +EMarkIndex::EMarkIndex() { + markCount = 0; + marks = 0; +} + +EMarkIndex::~EMarkIndex() { + if (markCount > 0 && marks) { + for (int n = 0; n < markCount; n++) + delete marks[n]; + delete marks; + marks = 0; + } +} + +EMark *EMarkIndex::insert(char *aName, char *aFileName, EPoint aPoint, EBuffer *aBuffer) { + int L = 0, R = markCount, M, cmp; + + assert(aName != 0 && aName[0] != 0); + assert(aFileName != 0 && aFileName[0] != 0); + + while (L < R) { + M = (L + R) / 2; + cmp = strcmp(aName, marks[M]->getName()); + if (cmp == 0) + return 0; + else if (cmp > 0) + L = M + 1; + else + R = M; + } + + EMark **newMarks = (EMark **)realloc(marks, + sizeof(marks[0]) * (markCount + 1)); + if (newMarks == 0) + return 0; + marks = newMarks; + + EMark *m = new EMark(aName, aFileName, aPoint, aBuffer); + if (m == 0) + return 0; + + memmove(marks + L + 1, marks + L, sizeof(marks[0]) * (markCount - L)); + markCount++; + marks[L] = m; + return m; +} + +EMark *EMarkIndex::insert(char *aName, EBuffer *aBuffer, EPoint aPoint) { + assert(aName != 0 && aName[0] != 0); + assert(aBuffer != 0); + assert(aBuffer->FileName != 0); + + return insert(aName, aBuffer->FileName, aPoint, aBuffer); +} + +EMark *EMarkIndex::locate(char *aName) { + int L = 0, R = markCount, M, cmp; + + assert(aName != 0 && aName[0] != 0); + + while (L < R) { + M = (L + R) / 2; + cmp = strcmp(aName, marks[M]->getName()); + if (cmp == 0) + return marks[M]; + else if (cmp > 0) + L = M + 1; + else + R = M; + } + return 0; +} + +int EMarkIndex::remove(char *aName) { + int L = 0, R = markCount, M, cmp; + + assert(aName != 0 && aName[0] != 0); + + while (L < R) { + M = (L + R) / 2; + cmp = strcmp(aName, marks[M]->getName()); + if (cmp == 0) { + EMark *m = marks[M]; + + memmove(marks + M, + marks + M + 1, + sizeof(marks[0]) * (markCount - M - 1)); + markCount--; + + EMark **newMarks = (EMark **)realloc(marks, + sizeof(marks[0]) * (markCount)); + if (newMarks != 0 || markCount == 0) + marks = newMarks; + + delete m; + return 1; + } else if (cmp > 0) + L = M + 1; + else + R = M; + } + return 0; +} + +int EMarkIndex::view(EView *aView, char *aName) { + EMark *m = locate(aName); + if (m) { + EBuffer *b = m->getBuffer(); + if (b == 0) { + if (FileLoad(0, m->getFileName(), 0, aView) == 0) + return 0; + if (retrieveForBuffer((EBuffer *)ActiveModel) == 0) + return 0; + b = (EBuffer *)ActiveModel; + } + aView->SwitchToModel(b); + return b->GotoBookmark(m->getName()); + } + return 0; +} + +int EMarkIndex::retrieveForBuffer(EBuffer *aBuffer) { + for (int n = 0; n < markCount; n++) + if (marks[n]->getBuffer() == 0 && + filecmp(aBuffer->FileName, marks[n]->getFileName()) == 0) + { + if (marks[n]->setBuffer(aBuffer) == 0) + return 0; + } + return 1; +} + +int EMarkIndex::storeForBuffer(EBuffer *aBuffer) { + for (int n = 0; n < markCount; n++) + if (marks[n]->getBuffer() == aBuffer) + if (marks[n]->removeBuffer(aBuffer) == 0) + return 0; + return 1; +} + +int EMarkIndex::saveToDesktop(FILE *fp) { + for (int n = 0; n < markCount; n++) { + EPoint p = marks[n]->getPoint(); + + // ??? file of buffer or of mark? (different if file renamed) ??? + // perhaps marks should be duplicated? + fprintf(fp, "M|%d|%d|%s|%s\n", + p.Row, p.Col, + marks[n]->getName(), + marks[n]->getFileName()); + } + return 1; +} + +// needs performance fixes (perhaps a redesign ?) + +EMark *EMarkIndex::pushMark(EBuffer *aBuffer, EPoint P) { + int stackTop = -1; + + for (int n = 0; n < markCount; n++) { + char *name = marks[n]->getName(); + if (name && name[0] == '#' && isdigit(name[1])) { + int no = atoi(name + 1); + if (no > stackTop) + stackTop = no; + } + } + char name[20]; + sprintf(name, "#%d", stackTop + 1); + return insert(name, aBuffer, P); +} + +int EMarkIndex::popMark(EView *aView) { + int stackTop = -1; + + for (int n = 0; n < markCount; n++) { + char *name = marks[n]->getName(); + if (name && name[0] == '#' && isdigit(name[1])) { + int no = atoi(name + 1); + if (no > stackTop) + stackTop = no; + } + } + if (stackTop == -1) + return 0; + char name[20]; + sprintf(name, "#%d", stackTop); + if (view(aView, name) == 0) + return 0; + assert(remove(name) == 1); + return 1; +} diff --git a/src/e_mark.h b/src/e_mark.h new file mode 100644 index 0000000..eb24dbc --- /dev/null +++ b/src/e_mark.h @@ -0,0 +1,57 @@ +#ifndef __EMARK_H +#define __EMARK_H + +class EMark { +public: + EMark(char *aName, char *aFileName, EPoint aPoint, EBuffer *aBuffer = 0); + ~EMark(); + + int setBuffer(EBuffer *aBuffer); + int removeBuffer(EBuffer *aBuffer); + + char *getName() { return Name; } + char *getFileName() { return FileName; } + EPoint &getPoint(); + EBuffer *getBuffer() { return Buffer; } +private: + /* bookmark */ + char *Name; + EPoint Point; + char *FileName; + + /* bookmark in file */ + EBuffer *Buffer; +}; + +class EMarkIndex { +public: + EMarkIndex(); + ~EMarkIndex(); + + EMark *insert(char *aName, char *aFileName, EPoint aPoint, EBuffer *aBuffer = 0); + EMark *insert(char *aName, EBuffer *aBuffer, EPoint aPoint); + EMark *locate(char *aName); + int remove(char *aName); + int view(EView *aView, char *aName); + +// int MarkPush(EBuffer *B, EPoint P); +// int MarkPop(EView *V); +// int MarkSwap(EView *V, EBuffer *B, EPoint P); +// int MarkNext(EView *V); + // int MarkPrev(EView *V); + EMark *pushMark(EBuffer *aBuffer, EPoint P); + int popMark(EView *aView); + + int retrieveForBuffer(EBuffer *aBuffer); + int storeForBuffer(EBuffer *aBuffer); + + int saveToDesktop(FILE *fp); + +private: + int markCount; + EMark **marks; +}; + +extern EMarkIndex markIndex; + +#endif diff --git a/src/e_os2.cpp b/src/e_os2.cpp new file mode 100644 index 0000000..e922f3f --- /dev/null +++ b/src/e_os2.cpp @@ -0,0 +1,39 @@ +/* e_os2.cpp + * + * Copyright (c) 1997, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +// Win32 (NT) specific routines + +#include "fte.h" + +int EView::SysShowHelp(ExState &State, const char *word) { + char file[MAXPATH] = ""; + char cmd[1024]; + + if (State.GetStrParam(this, file, sizeof(file) - 1) == 0) + if (MView->Win->GetStr("Help file", + sizeof(file) - 1, file, HIST_DEFAULT) == 0) + return 0; + + char wordAsk[64] = ""; + if (word == 0) { + if (State.GetStrParam(this, wordAsk, sizeof(wordAsk) - 1) == 0) + if (MView->Win->GetStr("Keyword", + sizeof(wordAsk) - 1, wordAsk, HIST_DEFAULT) == 0) + return 0; + word = wordAsk; + } + + sprintf(cmd, "%s %s %s", HelpCommand, file, word); + + if (system(cmd) != 0) { + Msg(S_ERROR, "Failed to start view.exe!"); + return 0; + } + return 1; +} diff --git a/src/e_print.cpp b/src/e_print.cpp new file mode 100644 index 0000000..9f55608 --- /dev/null +++ b/src/e_print.cpp @@ -0,0 +1,194 @@ +/* e_print.cpp + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#include "fte.h" + +int EBuffer::BlockPrint() { + static char cr = 13; + static char lf = 10; + EPoint B, E; + int L; + int A, Z; + PELine LL; + FILE *fp; + int bc = 0, lc = 0; + int error = 0; + + AutoExtend = 0; + if (CheckBlock() == 0) return 0; + if (RCount == 0) return 0; + B = BB; + E = BE; + Msg(S_INFO, "Printing to %s...", PrintDevice); +#if !defined(__IBMCPP__) && !defined(__WATCOMC__) + if (PrintDevice[0] == '|') + fp = popen(PrintDevice + 1, "w"); + else +#endif + fp = fopen(PrintDevice, "w"); + if (fp == NULL) { + Msg(S_INFO, "Failed to write to %s", PrintDevice); + return 0; + } + for (L = B.Row; L <= E.Row; L++) { + A = -1; + Z = -1; + LL = RLine(L); + switch (BlockMode) { + case bmLine: + if (L < E.Row) { + A = 0; + Z = LL->Count; + } + break; + case bmColumn: + if (L < E.Row) { + A = CharOffset(LL, B.Col); + Z = CharOffset(LL, E.Col); + } + break; + case bmStream: + if (B.Row == E.Row) { + A = CharOffset(LL, B.Col); + Z = CharOffset(LL, E.Col); + } else if (L == B.Row) { + A = CharOffset(LL, B.Col); + Z = LL->Count; + } else if (L < E.Row) { + A = 0; + Z = LL->Count; + } else if (L == E.Row) { + A = 0; + Z = CharOffset(LL, E.Col); + } + break; + } + if (A != -1 && Z != -1) { + if (A < LL->Count) { + if (Z > LL->Count) + Z = LL->Count; + if (Z > A) { + if ((int)(fwrite(LL->Chars + A, 1, Z - A, fp)) != Z - A) { + error++; + break; + } else + bc += Z - A; + } + } + if (BFI(this, BFI_AddCR) == 1) + if (fwrite(&cr, 1, 1, fp) != 1) { + error++; + break; + } else + bc++; + if (BFI(this, BFI_AddLF) == 1) + if (fwrite(&lf, 1, 1, fp) != 1) { + error++; + break; + } else { + bc++; + lc++; + } + if ((lc % 200) == 0) + Msg(S_INFO, "Printing, %d lines, %d bytes.", lc, bc); + + } + } + if (!error) { + fwrite("\f\n", 2, 1, fp); +#if !defined(__IBMCPP__) && !defined(__WATCOMC__) + if (PrintDevice[0] == '|') + pclose(fp); + else +#endif + fclose(fp); + Msg(S_INFO, "Printing %d lines, %d bytes.", lc, bc); + return 1; + } +#if !defined(__IBMCPP__) && !defined(__WATCOMC__) + if (PrintDevice[0] == '|') + pclose(fp); + else +#endif + fclose(fp); + Msg(S_INFO, "Failed to write to %s", PrintDevice); + return 0; +} + + +int EBuffer::FilePrint() { + static char cr = 13; + static char lf = 10; + int l; + FILE *fp; + unsigned long ByteCount = 0; + int BChars; + + Msg(S_INFO, "Printing %s to %s...", FileName, PrintDevice); +#if !defined(__IBMCPP__) && !defined(__WATCOMC__) + if (PrintDevice[0] == '|') + fp = popen(PrintDevice + 1, "w"); + else +#endif + fp = fopen(PrintDevice, "w"); + if (fp == NULL) { + Msg(S_ERROR, "Error printing %s to %s.", FileName, PrintDevice); + return 0; + } + BChars = 0; + for (l = 0; l < RCount; l++) { + if ((int) sizeof(FileBuffer) - (BChars + 2) < RLine(l)->Count) { + if (BChars) { + ByteCount += BChars; + Msg(S_INFO, "Printing: %d lines, %d bytes.", l, ByteCount); + if ((int)(fwrite(FileBuffer, 1, BChars, fp)) != BChars) goto fail; + BChars = 0; + } + } + if (RLine(l)->Count > int(sizeof(FileBuffer)) - 2) { + assert(BChars == 0); + ByteCount += RLine(l)->Count; + Msg(S_INFO, "Printing: %d lines, %d bytes.", l, ByteCount); + if (int(fwrite(RLine(l)->Chars, 1, RLine(l)->Count, fp)) != RLine(l)->Count) goto fail; + } else { + memcpy(FileBuffer + BChars, RLine(l)->Chars, RLine(l)->Count); + BChars += RLine(l)->Count; + } + if ((l < RCount - 1) || BFI(this, BFI_ForceNewLine)) { + assert(int(sizeof(FileBuffer)) >= BChars + 2); + if (BFI(this, BFI_AddCR) == 1) FileBuffer[BChars++] = cr; + if (BFI(this, BFI_AddLF) == 1) FileBuffer[BChars++] = lf; + } + } + if (BChars) { + ByteCount += BChars; + Msg(S_INFO, "Printing: %d lines, %d bytes.", l, ByteCount); + if ((int)(fwrite(FileBuffer, 1, BChars, fp)) != BChars) goto fail; + } + BChars = 0; +#if !defined(__IBMCPP__) && !defined(__WATCOMC__) + if (PrintDevice[0] == '|') + pclose(fp); + else +#endif + fclose(fp); + Msg(S_INFO, "Printed %s.", FileName); + return 1; +fail: + if (fp != NULL) { +#if !defined(__IBMCPP__) && !defined(__WATCOMC__) + if (PrintDevice[0] == '|') + pclose(fp); + else +#endif + fclose(fp); + } + Msg(S_ERROR, "Error printing %s to %s.", FileName, PrintDevice); + return 0; +} diff --git a/src/e_redraw.cpp b/src/e_redraw.cpp new file mode 100644 index 0000000..ceb88a0 --- /dev/null +++ b/src/e_redraw.cpp @@ -0,0 +1,596 @@ +/* e_redraw.cpp + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#include "fte.h" + +int EBuffer::GetMap(int Row, int *StateLen, hsState **StateMap) { + hlState State = 0; + + Rehilit(Row); + + *StateLen = LineChars(Row); + if (Row > 0) State = RLine(Row - 1)->StateE; + if (*StateLen > 0) { + PELine L = RLine(Row); + int ECol; + + *StateMap = (hsState *) malloc(*StateLen); + if (*StateMap == 0) return 0; + +#ifdef CONFIG_SYNTAX_HILIT + if (BFI(this, BFI_HilitOn) == 1 && HilitProc != 0) + HilitProc(this, Row, 0, 0, *StateLen, L, State, *StateMap, &ECol); + else +#endif + Hilit_Plain(this, Row, 0, 0, *StateLen, L, State, *StateMap, &ECol); + // if (L->StateE != State) { + // L->StateE = State; + // } + } else { + *StateLen = 1; + *StateMap = (hsState *) malloc(1); + if (*StateMap == 0) return 0; + (*StateMap)[0] = (hsState) (State & 0xFF); + } + return 1; +} + +void EBuffer::FullRedraw() { // redraw all views + EView *V = View; + EEditPort *W; + + while (V) { + W = GetViewVPort(V); + Draw(W->TP.Row, W->TP.Row + W->Rows); + V = V->Next; + if (V == View) + break; + } +} + +void EBuffer::Hilit(int FromRow) { + if (FromRow != -1) { + if (StartHilit == -1) + StartHilit = FromRow; + else if (FromRow < StartHilit) + StartHilit = FromRow; + } +} + +void EBuffer::Rehilit(int ToRow) { + hlState State; + int HilitX; + PELine L; + int ECol; + + if (StartHilit == -1) // all ok + return ; + + if (BFI(this, BFI_MultiLineHilit) == 0) // everything handled in redisplay + return; + + if (ToRow <= StartHilit) // will be handled in redisplay + return; + + if (ToRow >= RCount) + ToRow = RCount; + + HilitX = 1; + while ((StartHilit < RCount) && ((StartHilit < ToRow) || HilitX)) { + L = RLine(StartHilit); + + HilitX = 0; + if (StartHilit > 0) + State = RLine(StartHilit - 1)->StateE; + else + State = 0; + + if (BFI(this, BFI_HilitOn) == 1 && HilitProc != 0) { + HilitProc(this, StartHilit, 0, 0, 0, L, State, 0, &ECol); + } else { + Hilit_Plain(this, StartHilit, 0, 0, 0, L, State, 0, &ECol); + } + if (L->StateE != State) { + HilitX = 1; + L->StateE = State; + } + Draw(StartHilit, StartHilit); // ? + if (StartHilit > EndHilit) + EndHilit = StartHilit; + if (HilitX == 0) // jump over (can we always do this ?) + if (StartHilit < EndHilit) { + StartHilit = EndHilit; + } + StartHilit++; + } +} + +void EBuffer::Draw(int Row0, int RowE) { + // printf("r0 = %d, re = %d\n", Row0, RowE); + // printf("m = %d, max = %d, rts = %d\n", MinRedraw, MaxRedraw, RedrawToEos); + if (Row0 == -1) Row0 = 0; + if ((Row0 < MinRedraw) || (MinRedraw == -1)) { + MinRedraw = Row0; + if (MaxRedraw == -1) MaxRedraw = MinRedraw; + } + if (RowE == -1) { + RedrawToEos = 1; + MaxRedraw = MinRedraw; + } else if (((RowE > MaxRedraw) || (MaxRedraw == -1)) && (RowE != -1)) + MaxRedraw = RowE; + // printf("m = %d, max = %d, rts = %d\n", MinRedraw, MaxRedraw, RedrawToEos); +} + +void EBuffer::DrawLine(TDrawBuffer B, int VRow, int C, int W, int &HilitX) { + hlState State; + int StartPos, EndPos; + + HilitX = 0; + MoveChar(B, 0, W, ' ', hcPlain_Background, W); + // if ((VRow == VCount - 1) && !BFI(this, BFI_ForceNewLine)) { + // if (BFI(this, BFI_ShowMarkers)) + // MoveChar(B, 0, W, EOF_MARKER, hcPlain_Markers, W); + // } + if (VRow < VCount) { + int Row = VToR(VRow); + PELine L = RLine(Row); + int ECol = 0; + + if (Row > 0) State = RLine(Row - 1)->StateE; + else State = 0; +#ifdef CONFIG_SYNTAX_HILIT + if (BFI(this, BFI_HilitOn) == 1 && HilitProc != 0) + HilitProc(this, Row, B, C, W, L, State, 0, &ECol); + else +#endif + Hilit_Plain(this, Row, B, C, W, L, State, 0, &ECol); + if (L->StateE != State) { + HilitX = 1; + L->StateE = State; + } + if (BFI(this, BFI_ShowMarkers)) { + MoveChar(B, ECol - C, W, ConGetDrawChar((Row == RCount - 1) ? DCH_EOF : DCH_EOL), hcPlain_Markers, 1); + ECol += 1; + } + if (Row < RCount) { + int f; + int Folded = 0; + static char fold[20]; + int l; + + f = FindFold(Row); + if (f != -1) { + if (FF[f].open == 1) { + l = sprintf(fold, "[%d]", FF[f].level); + MoveStr(B, ECol - C + 1, W, fold, hcPlain_Folds, 10); + ECol += l; + } else { + if (VRow < VCount - 1) { + Folded = Vis(VRow + 1) - Vis(VRow) + 1; + } else if (VRow < VCount) { + Folded = RCount - (VRow + Vis(VRow)); + } + l = sprintf(fold, "(%d:%d)", FF[f].level, Folded); + MoveStr(B, ECol - C + 1, W, fold, hcPlain_Folds, 10); + ECol += l; + MoveAttr(B, 0, W, hcPlain_Folds, W); + } + } + } + if (BB.Row != -1 && BE.Row != -1 && Row >= BB.Row && Row <= BE.Row) { + switch(BlockMode) { + case bmLine: + StartPos = 0; + if (Row == BE.Row) EndPos = 0; + else EndPos = W; + break; + case bmColumn: + StartPos = BB.Col - C; + if (Row == BE.Row) EndPos = BB.Col - C; + else EndPos = BE.Col - C; + break; + case bmStream: + if (Row == BB.Row && Row == BE.Row) { + StartPos = BB.Col - C; + EndPos = BE.Col - C; + } else if (Row == BB.Row) { + StartPos = BB.Col - C; + EndPos = W; + } else if (Row == BE.Row) { + StartPos = 0; + EndPos = BE.Col - C; + } else { + StartPos = 0; + EndPos = W; + } + break; + default: + StartPos = EndPos = 0; + break; + } + if (BFI(this, BFI_SeeThruSel)) + MoveBgAttr(B, StartPos, W, hcPlain_Selected, EndPos - StartPos); + else + MoveAttr(B, StartPos, W, hcPlain_Selected, EndPos - StartPos); + } + if (Match.Row != -1 && Match.Col != -1) { + if (Row == Match.Row) { + if (BFI(this, BFI_SeeThruSel)) + MoveBgAttr(B, Match.Col - C, W, hcPlain_Found, MatchLen); + else + MoveAttr(B, Match.Col - C, W, hcPlain_Found, MatchLen); + } + } + } else if (VRow == VCount) { + if (BFI(this, BFI_ShowMarkers)) + MoveChar(B, 0, W, ConGetDrawChar(DCH_END), hcPlain_Markers, W); + } +} + +void EBuffer::Redraw() { + int HilitX; + EView *V; + EEditPort *W; + int Row; + TDrawBuffer B; + char s[256]; + ChColor SColor; + int RowA, RowZ; + + { + int W1, H1; + if (!(View && View->MView)) + return; + View->MView->ConQuerySize(&W1, &H1); + + if (H1 < 1 || W1 < 1) return; + } + // printf("Redraw\n"); + if (CP.Row >= VCount) CP.Row = VCount - 1; + if (CP.Row < 0) CP.Row = 0; + + CheckBlock(); + V = View; /* check some window data */ + if (!V) { + MinRedraw = MaxRedraw = -1; + RedrawToEos = 0; + return; + } + if (View == 0 || View->MView == 0 || View->MView->Win == 0) + return ; + + for ( ; V; V = V->NextView) { + // printf("Checking\x7\n"); + if (V->Model != this) + assert(1 == 0); + + W = GetViewVPort(V); + + if (W->Rows < 1 || W->Cols < 1) + continue; + + if (V == View) { + int scrollJumpX = Min(ScrollJumpX, W->Cols / 2); + int scrollJumpY = Min(ScrollJumpY, W->Rows / 2); + int scrollBorderX = Min(ScrollBorderX, W->Cols / 2); + int scrollBorderY = Min(ScrollBorderY, W->Rows / 2); + + W->CP = CP; + TP = W->TP; + + if (W->ReCenter) { + W->TP.Row = CP.Row - W->Rows / 2; + W->TP.Col = CP.Col - W->Cols + 8; + W->ReCenter = 0; + } + + if (W->TP.Row + scrollBorderY > CP.Row) W->TP.Row = CP.Row - scrollJumpY + 1 - scrollBorderY; + if (W->TP.Row + W->Rows - scrollBorderY <= CP.Row) W->TP.Row = CP.Row - W->Rows + 1 + scrollJumpY - 1 + scrollBorderY; + if (!WeirdScroll) + if (W->TP.Row + W->Rows >= VCount) W->TP.Row = VCount - W->Rows; + if (W->TP.Row < 0) W->TP.Row = 0; + + if (W->TP.Col + scrollBorderX > CP.Col) W->TP.Col = CP.Col - scrollJumpX - scrollBorderX; + if (W->TP.Col + W->Cols - scrollBorderX <= CP.Col) W->TP.Col = CP.Col - W->Cols + scrollJumpX + scrollBorderX; + if (W->TP.Col < 0) W->TP.Col = 0; + + if (W->OldTP.Row != -1 && W->OldTP.Col != -1 && RedrawToEos == 0) { + + if ((W->OldTP.Row != W->TP.Row) || (W->OldTP.Col != W->TP.Col)) { + int A, B; + int DeltaX, DeltaY; + int Rows = W->Rows; + int Delta1 = 0, Delta2 = 0; + + DeltaY = W->TP.Row - W->OldTP.Row ; + DeltaX = W->TP.Col - W->OldTP.Col; + + if ((DeltaX == 0) && (-Rows < DeltaY) && (DeltaY < Rows)) { + if (DeltaY < 0) { + W->ScrollY(DeltaY); + A = W->TP.Row; + B = W->TP.Row - DeltaY; + } else { + W->ScrollY(DeltaY); + A = W->TP.Row + Rows - DeltaY; + B = W->TP.Row + Rows; + } + } else { + A = W->TP.Row; + B = W->TP.Row + W->Rows; + } + if (A >= VCount) { + Delta1 = A - VCount + 1; + A = VCount - 1; + } + if (B >= VCount) { + Delta2 = B - VCount + 1; + B = VCount - 1; + } + if (A < 0) A = 0; + if (B < 0) B = 0; + Draw(VToR(A) + Delta1, VToR(B) + Delta2); + } + } else { + int A = W->TP.Row; + int B = A + W->Rows; + int Delta = 0; + + if (B > VCount) { + Delta += B - VCount; + B = VCount; + } + int LastV = VToR(VCount - 1); + int B1 = (B == VCount) ? RCount : VToR(B); + + if (B1 >= LastV) { + Delta += B1 - LastV; + B1 = LastV; + } + if (B1 < 0) B1 = 0; + Draw(VToR(A), B1 + Delta); + } + + W->OldTP = W->TP; + TP = W->TP; + } + if (W->CP.Row >= VCount) W->CP.Row = VCount - 1; + if (W->CP.Row < 0) W->CP.Row = 0; + if (W->TP.Row > W->CP.Row) W->TP.Row = W->CP.Row; + if (W->TP.Row < 0) W->TP.Row = 0; + + if (V->MView->IsActive()) // hack + SColor = hcStatus_Active; + else + SColor = hcStatus_Normal; + MoveChar(B, 0, W->Cols, ' ', SColor, W->Cols); + + if (V->MView->Win->GetViewContext() == V->MView) { + V->MView->Win->SetSbVPos(W->TP.Row, W->Rows, VCount + (WeirdScroll ? W->Rows - 1 : 0)); + V->MView->Win->SetSbHPos(W->TP.Col, W->Cols, 1024 + (WeirdScroll ? W->Cols - 1 : 0)); + } + + if (V->CurMsg == 0) { + { + int CurLine = W->CP.Row; + int ActLine = VToR(W->CP.Row); + int CurColumn = W->CP.Col; + int CurPos = CharOffset(RLine(ActLine), CurColumn); + int NumLines = RCount; + int NumChars = RLine(ActLine)->Count; + // int NumColumns = ScreenPos(Line(CurLine), NumChars); + char *fName = FileName; + unsigned char CurCh = 0xFF; + int lf = strlen(fName); + char CCharStr[20] = ""; + + if (lf > 34) fName += lf - 34; + + if (CurPos < NumChars) { + CurCh = VLine(CurLine)->Chars[CurPos]; + sprintf(CCharStr, "%3u,%02X", CurCh, CurCh); + } else { + if (CurPos > NumChars) strcpy(CCharStr, " "); + else if (CurLine < NumLines - 1) strcpy(CCharStr, " EOL"); + else strcpy(CCharStr, " EOF"); + } + + sprintf(s, "%04d:%02d %c%c%c%c%c %.6s %c" +#ifdef DOS + " %lu " +#endif + , + // CurLine + 1, + ActLine + 1, + CurColumn + 1, + // CurPos + 1, + (BFI(this, BFI_Insert)) ? 'I' : ' ', + (BFI(this, BFI_AutoIndent)) ? 'A' : ' ', + // (BFI(this, BFI_ExpandTabs))?'T':' ', + (BFI(this, BFI_MatchCase)) ? 'C' : ' ', + AutoExtend ? + ( + (BlockMode == bmStream) ? 's' : + (BlockMode == bmLine) ? 'l' : 'c' + ) : + ((BlockMode == bmStream) ? 'S' : + (BlockMode == bmLine) ? 'L': 'C' + ), +#ifdef CONFIG_WORDWRAP + (BFI(this, BFI_WordWrap) == 3) ? 't' : + (BFI(this, BFI_WordWrap) == 2) ? 'W' : + (BFI(this, BFI_WordWrap) == 1) ? 'w' : + ' ', +#endif + // (BFI(this, BFI_Undo))?'U':' ', + // (BFI(this, BFI_Trim))?'E':' ', + // (Flags.KeepBackups)?'B':' ', + Mode->fName, + (Modified != 0)?'*':(BFI(this, BFI_ReadOnly))?'%':' ' +#ifdef DOS + ,coreleft() +#endif + ); + + int l = strlen(s); + int fw = W->Cols - l; + int fl = strlen(FileName); + char num[10]; + + MoveStr(B, 0, W->Cols, s, SColor, W->Cols); + sprintf(num, " %s %d", CCharStr, ModelNo); + MoveStr(B, W->Cols - strlen(num), W->Cols, num, SColor, W->Cols); + + fw -= strlen(num); + + if (fl > fw) { + MoveStr(B, l, W->Cols, FileName + fl - fw, SColor, W->Cols); + } else { + MoveStr(B, l, W->Cols, FileName, SColor, W->Cols); + } + } + } else { + MoveStr(B, 0, W->Cols, V->CurMsg, SColor, W->Cols); + } + if (V->MView->Win->GetStatusContext() == V->MView) { + V->MView->ConPutBox(0, W->Rows, W->Cols, 1, B); + if (V->MView->IsActive()) { + V->MView->ConShowCursor(); + V->MView->ConSetCursorPos(W->CP.Col - W->TP.Col, W->CP.Row - W->TP.Row); + if (BFI(this, BFI_Insert)) { + V->MView->ConSetCursorSize(CursorInsSize[0], CursorInsSize[1]); + } else { + V->MView->ConSetCursorSize(CursorOverSize[0], CursorOverSize[1]); + } + } + } + } + + Rehilit(VToR(CP.Row)); + + if (BFI(this, BFI_AutoHilitParen) == 1) { + if (Match.Row == -1 && Match.Col == -1) + HilitMatchBracket(); + } + + // if ((Window == WW) && (MinRedraw == -1)) + // MaxRedraw = MinRedraw = VToR(CP.Row); + + //printf("\n\nMinRedraw = %d, MaxRedraw = %d", MinRedraw, MaxRedraw); + if (MinRedraw == -1) + return; + + // printf("Will redraw: %d to %d, to eos = %d\n", MinRedraw, MaxRedraw, RedrawToEos); + if (MinRedraw >= VCount) MinRedraw = VCount - 1; + if (MinRedraw < 0) MinRedraw = 0; + // puts("xxx\x7"); + // printf("%d\n", MinRedraw); + Row = RowA = RToVN(MinRedraw); + // puts("xxx\x7"); + RowZ = MaxRedraw; + if (MaxRedraw != -1) { + int Delta = 0; + + if (MaxRedraw >= RCount) { + Delta = MaxRedraw - RCount + 1; + MaxRedraw = RCount - 1; + } + if (MaxRedraw < 0) MaxRedraw = 0; + // printf("%d\n", MaxRedraw); + RowZ = RToVN(MaxRedraw) + Delta; + } + // puts("xxx\x7"); + //printf("\nRowA = %d, RowZ = %d", RowA, RowZ); + + V = View; + while (V) { + if (V->Model != this) + assert(1 == 0); + + W = GetViewVPort(V); + + for (int R = W->TP.Row; R < W->TP.Row + W->Rows; R++) { + Row = R; + if ((Row >= RowA) && + (RedrawToEos || Row <= RowZ)) + { + DrawLine(B, Row, W->TP.Col, W->Cols, HilitX); + W->DrawLine(Row, B); + if (HilitX && Row == RowZ) + RowZ++; + } + } + V = V->NextView; + } + MinRedraw = MaxRedraw = -1; + RedrawToEos = 0; +} + +int EBuffer::GetHilitWord(int len, char *str, ChColor &clr, int IgnCase) { + char *p; + + if (Mode == 0 || Mode->fColorize == 0) + return 0; + + if (len >= CK_MAXLEN) + return 0; + +#ifdef CONFIG_WORD_HILIT + { + char s[CK_MAXLEN + 1]; + s[CK_MAXLEN] = 0; + memcpy(s, str, len); + s[len] = 0; + if (HilitFindWord(s)) { + clr = hcPlain_HilitWord; + return 1; + } + } +#endif + if (len < 1) return 0; + p = Mode->fColorize->Keywords.key[len]; + if (IgnCase) { + while (p && *p) { + if (strnicmp(p, str, len) == 0) { + clr = p[len]; + return 1; + } + p += len + 1; + } + } else { + while (p && *p) { + if (memcmp(p, str, len) == 0) { + clr = p[len]; + return 1; + } + p += len + 1; + } + } + if (0 && len < 128) { // disabled + char s[128]; + + memcpy(s, str, len); + s[len] = 0; + if (TagDefined(s)) { + //clr = 0x0A; + clr = Mode->fColorize->Colors[CLR_HexNumber]; + return 1; + } + } + + return 0; +} + +EEditPort *EBuffer::GetViewVPort(EView *V) { + return (EEditPort *)V->Port; +} + +EEditPort *EBuffer::GetVPort() { + return (EEditPort *)View->Port; +} diff --git a/src/e_regex.cpp b/src/e_regex.cpp new file mode 100644 index 0000000..603380c --- /dev/null +++ b/src/e_regex.cpp @@ -0,0 +1,1116 @@ +/* e_regex.cpp + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#include +#include +#include +#include +#include +#include "e_regex.h" + +//#define DEBUG + +static int RegCount = 0; + +#ifdef DEBUG +static void RxDump(int N, RxNode *n); +#endif + +static RxNode *NewNode(int aWhat) { + RxNode *N = (RxNode *) malloc(sizeof(RxNode)); + + if (N) { + memset(N, 0, sizeof(RxNode)); + N->fWhat = (short)aWhat; + } + return N; +} + +static RxNode *NewChar(char Ch) { + RxNode *A = NewNode(RE_CHAR); + + if (A) { + A->fChar = (char *)malloc(1); + A->fLen = 1; + A->fChar[0] = Ch; + } + return A; +} + +static RxNode *NewEscape(const char **const Regexp) { + char Ch = **Regexp; + ++*Regexp; + switch (Ch) { + case 0: return 0; + case 'a': Ch = '\a'; break; + case 'b': Ch = '\b'; break; + case 'f': Ch = '\f'; break; + case 'n': Ch = '\n'; break; + case 'r': Ch = '\r'; break; + case 't': Ch = '\t'; break; + case 'v': Ch = '\v'; break; + case 'e': Ch = 27; break; + case 's': return NewNode(RE_WSPACE); + case 'S': return NewNode(RE_NWSPACE); + case 'U': return NewNode(RE_UPPER); + case 'L': return NewNode(RE_LOWER); + case 'w': return NewNode(RE_WORD); + case 'W': return NewNode(RE_NWORD); + case 'd': return NewNode(RE_DIGIT); + case 'D': return NewNode(RE_NDIGIT); + case 'C': return NewNode(RE_CASE); + case 'c': return NewNode(RE_NCASE); + case 'N': + { + unsigned int N = 0; + unsigned int A = 0; + if (**Regexp == 0) return 0; + N = toupper(**Regexp) - 48; if (N > 9) return 0; + (*Regexp)++; + A = N * 100; + if (**Regexp == 0) return 0; + N = toupper(**Regexp) - 48; if (N > 9) return 0; + (*Regexp)++; + A = A + N * 10; + if (**Regexp == 0) return 0; + N = toupper(**Regexp) - 48; if (N > 9) return 0; + (*Regexp)++; + A = A + N; + Ch = (char)A; + } + break; + case 'o': + { + unsigned int N = 0; + unsigned int A = 0; + if (**Regexp == 0) return 0; + N = toupper(**Regexp) - 48; if (N > 7) return 0; + (*Regexp)++; + A = N * 64; + if (**Regexp == 0) return 0; + N = toupper(**Regexp) - 48; if (N > 7) return 0; + (*Regexp)++; + A = A + N * 8; + if (**Regexp == 0) return 0; + N = toupper(**Regexp) - 48; if (N > 7) return 0; + (*Regexp)++; + A = A + N; + Ch = (char)A; + } + break; + case 'x': + { + unsigned int N = 0; + unsigned int A = 0; + if (**Regexp == 0) return 0; + N = toupper(**Regexp) - 48; if (N > 9) N = N + 48 - 65 + 10; if (N > 15) return 0; + (*Regexp)++; + A = N << 4; + if (**Regexp == 0) return 0; + N = toupper(**Regexp) - 48; if (N > 9) N = N + 48 - 65 + 10; if (N > 15) return 0; + (*Regexp)++; + A = A + N; + Ch = (char)A; + } + break; + } + return NewChar(Ch); +} + + +#define NNN 32 // 8 * 32 = 256 (match set) + +#define SETOP(set,n) \ + do { \ + set[(unsigned char)(n) >> 3] |= (unsigned char)(1 << ((unsigned char)(n) & 7)); \ + } while (0) + +static RxNode *NewSet(const char ** const Regexp) { + unsigned char set[NNN]; + int s = 0; + int c = 0; + unsigned int i, xx; + unsigned char Ch, C1 = 0, C2 = 0; + int doset = 0; + + memset(set, 0, sizeof(set)); + s = 1; + if (**Regexp == '^') { + s = 0; + ++*Regexp; + } + c = 0; + + while (**Regexp) { + switch (Ch = *((*Regexp)++)) { + case ']': + if (doset == 1) return 0; + { + RxNode *N = NewNode(s?RE_INSET:RE_NOTINSET); + N->fChar = (char *) malloc(sizeof(set)); + N->fLen = sizeof(set); + if (N->fChar == 0) return 0; + memcpy(N->fChar, (char *) set, sizeof(set)); + return N; + } + case '\\': + switch (Ch = *((*Regexp)++)) { + case 0: return 0; + case 'a': Ch = '\a'; break; + case 'b': Ch = '\b'; break; + case 'f': Ch = '\f'; break; + case 'n': Ch = '\n'; break; + case 'r': Ch = '\r'; break; + case 't': Ch = '\t'; break; + case 'v': Ch = '\v'; break; + case 'e': Ch = 27; break; + case 'N': + { + unsigned int N = 0; + unsigned int A = 0; + if (**Regexp == 0) return 0; + N = toupper(**Regexp) - 48; if (N > 9) return 0; + (*Regexp)++; + A = N * 100; + if (**Regexp == 0) return 0; + N = toupper(**Regexp) - 48; if (N > 9) return 0; + (*Regexp)++; + A = A + N * 10; + if (**Regexp == 0) return 0; + N = toupper(**Regexp) - 48; if (N > 9) return 0; + (*Regexp)++; + A = A + N; + Ch = (unsigned char)A; + } + break; + case 'o': + { + unsigned int N = 0; + unsigned int A = 0; + if (**Regexp == 0) return 0; + N = toupper(**Regexp) - 48; if (N > 7) return 0; + (*Regexp)++; + A = N * 64; + if (**Regexp == 0) return 0; + N = toupper(**Regexp) - 48; if (N > 7) return 0; + (*Regexp)++; + A = A + N * 8; + if (**Regexp == 0) return 0; + N = toupper(**Regexp) - 48; if (N > 7) return 0; + (*Regexp)++; + A = A + N; + Ch = (unsigned char)A; + } + break; + case 'x': + { + unsigned int N = 0; + unsigned int A = 0; + if (**Regexp == 0) return 0; + N = toupper(**Regexp) - 48; if (N > 9) N = N + 48 - 65 + 10; if (N > 15) return 0; + (*Regexp)++; + A = N << 4; + if (**Regexp == 0) return 0; + N = toupper(**Regexp) - 48; if (N > 9) N = N + 48 - 65 + 10; if (N > 15) return 0; + (*Regexp)++; + A = A + N; + Ch = (unsigned char)A; + } + break; + case 's': + c += 4; + SETOP(set, '\n'); + SETOP(set, '\t'); + SETOP(set, ' '); + SETOP(set, '\r'); + continue; + case 'S': + for (xx = 0; xx <= 255; xx++) { + if (xx != ' ' && xx != '\t' && xx != '\n' && xx != '\r') { + c++; + SETOP(set, xx); + } + } + continue; + case 'w': + for (xx = 0; xx <= 255; xx++) { + if (isalnum(xx)) { + c++; + SETOP(set, xx); + } + } + break; + case 'W': + for (xx = 0; xx <= 255; xx++) { + if (!isalnum(xx)) { + c++; + SETOP(set, xx); + } + } + break; + case 'd': + for (xx = 0; xx <= 255; xx++) { + if (isdigit(xx)) { + c++; + SETOP(set, xx); + } + } + break; + case 'D': + for (xx = 0; xx <= 255; xx++) { + if (!isdigit(xx)) { + c++; + SETOP(set, xx); + } + } + break; + case 'U': + for (xx = 'A'; xx <= 'Z'; xx++) { + c++; + SETOP(set, xx); + } + continue; + case 'L': + for (xx = 'a'; xx <= 'z'; xx++) { + c++; + SETOP(set, xx); + } + continue; + } + break; + } + if (doset == 0 && ((**Regexp) == '-')) { + doset = 1; + C1 = Ch; + ++*Regexp; + continue; + } else if (doset == 1) { + C2 = Ch; + if (C2 < C1) return 0; + for(i = C1; i <= C2; i++) SETOP(set, i); + doset = 0; + continue; + } + c++; + SETOP(set, Ch); + } + return 0; +} + +static int AddNode(RxNode **F, RxNode **N, RxNode *A) { + if (A) { + if (*F) { + (*N)->fNext = A; + A->fPrev = (*N); + *N = A; + } else { + (*N) = (*F) = A; + A->fPrev = A->fNext = 0; + } + return 1; + } + return 0; +} + +static int CountWidth(RxNode *N) { + int w = 0; + + while (N) { + if (N->fWhat < 32) w += 0; + else if (N->fWhat >= 32 && N->fWhat < 64) + w += 1; + N = N->fNext; + } + return w; +} + +static int MakeSub(RxNode **F, RxNode **N, char What) { + //printf("MakeSub: %c\n", What); + if (*N) { + RxNode *No; + RxNode *New; + RxNode *Jump, *Skip; + RxNode *Last = (*N); + + if (Last->fWhat & RE_GROUP) { + RxNode *P = Last->fPrev; + int C = 1; + + while ((C > 0) && P) { + //puts("backtracking...-----"); + //RxDump(0, P); + if (P->fWhat & RE_GROUP) { + if (P->fWhat & RE_CLOSE) C++; + else C--; + } + Last = P; + if (C == 0) break; + P = P->fPrev; + } + //printf("P = %s, c = %d", P ? "ok":"null", C); + if (C != 0) return 0; + } + assert(Last); + if (What != '?' && What != '|') + if (CountWidth(Last) == 0) { + // puts("FAILED count"); + return 0; + } + switch (What) { + case '?': /* BRANCH x NOTHING */ + New = NewNode(RE_BRANCH | RE_GREEDY | What); + No = NewNode(RE_NOTHING); + if (!New || !No) return 0; + No->fPrev = *N; + if (*N) + (*N)->fNext = No; + New->fNext = Last; + New->fPrev = Last->fPrev; + Last->fPrev = New; + if (New->fPrev) { + New->fPrev->fNext = New; + } else { + *F = New; + } + New->fPtr = No; + No->fPtr = New; + *N = No; + //puts("BRANCH ?"); + break; + + case '*': + case '@': + New = NewNode(RE_BRANCH | What | ((What == '*') ? RE_GREEDY : 0)); + Jump = NewNode(RE_JUMP); + No = NewNode(RE_NOTHING); + + if (!New || !No || !Jump) return 0; + No->fPrev = Jump; + Jump->fNext = No; + Jump->fPrev = *N; + if (*N) + (*N)->fNext = Jump; + New->fNext = Last; + New->fPrev = Last->fPrev; + Last->fPrev = New; + if (New->fPrev) { + New->fPrev->fNext = New; + } else { + *F = New; + } + New->fPtr = No; + No->fPtr = New; + Jump->fPtr = New; + *N = No; + //puts("BRANCH *"); + break; + + case '#': + case '+': + New = NewNode(RE_BRANCH | What | ((What == '+') ? RE_GREEDY : 0)); + Skip = NewNode(RE_JUMP); + Jump = NewNode(RE_JUMP); + No = NewNode(RE_NOTHING); + + if (!New || !No || !Jump) return 0; + No->fPrev = Jump; + Jump->fPrev = *N; + Jump->fNext = No; + + Skip->fNext = New; + New->fPrev = Skip; + if (*N) + (*N)->fNext = Jump; + New->fNext = Last; + Skip->fPrev = Last->fPrev; + Last->fPrev = New; + if (Skip->fPrev) { + Skip->fPrev->fNext = Skip; + } else { + *F = Skip; + } + New->fPtr = No; + No->fPtr = New; + Jump->fPtr = New; + Skip->fPtr = Last; + *N = No; + //puts("BRANCH +"); + break; + case '|': + New = NewNode(RE_BRANCH | RE_GREEDY | What); + Jump = NewNode(RE_BREAK); + No = NewNode(RE_NOTHING); + + if (!New || !No || !Jump) return 0; + No->fPrev = Jump; + Jump->fNext = No; + Jump->fPrev = *N; + if (*N) + (*N)->fNext = Jump; + New->fNext = Last; + New->fPrev = Last->fPrev; + Last->fPrev = New; + if (New->fPrev) { + New->fPrev->fNext = New; + } else { + *F = New; + } + New->fPtr = No; + No->fPtr = New; + Jump->fPtr = New; + *N = No; + //puts("BRANCH |"); + break; + } + return 1; + } + return 0; +} + +#define CHECK(n) do { if ((n) == 0) { return 0;} } while (0) + +static RxNode *RxComp(const char **const Regexp) { + RxNode *F = 0; + RxNode *N = 0; + int C; + char Ch; + + while (**Regexp) { + // puts(*Regexp); + switch (Ch = (*(*Regexp)++)) { + case '?': + case '*': + case '+': + case '@': + case '#': + case '|': + CHECK(MakeSub(&F, &N, Ch)); + break; + case '}': + case ')': + return F; + case '{': + CHECK(AddNode(&F, &N, NewNode(RE_GROUP | RE_OPEN))); + CHECK(AddNode(&F, &N, RxComp(Regexp))); + while (N->fNext) N = N->fNext; + CHECK(AddNode(&F, &N, NewNode(RE_GROUP | RE_CLOSE))); + break; + case '(': + C = ++RegCount; + CHECK(AddNode(&F, &N, NewNode(RE_GROUP | RE_OPEN | RE_MEM | C))); + CHECK(AddNode(&F, &N, RxComp(Regexp))); + while (N->fNext) N = N->fNext; + CHECK(AddNode(&F, &N, NewNode(RE_GROUP | RE_CLOSE | RE_MEM | C))); + break; + case '\\':CHECK(AddNode(&F, &N, NewEscape(Regexp))); break; + case '[': CHECK(AddNode(&F, &N, NewSet(Regexp))); break; + case '^': CHECK(AddNode(&F, &N, NewNode(RE_ATBOL))); break; + case '$': CHECK(AddNode(&F, &N, NewNode(RE_ATEOL))); break; + case '.': CHECK(AddNode(&F, &N, NewNode(RE_ANY))); break; + case '<': CHECK(AddNode(&F, &N, NewNode(RE_ATBOW))); break; + case '>': CHECK(AddNode(&F, &N, NewNode(RE_ATEOW))); break; + default: + --*Regexp; + CHECK(AddNode(&F, &N, NewChar(**Regexp))); + ++*Regexp; + break; + } + } + return F; +} + +RxNode *RxOptimize(RxNode *rx) { + return rx; +} + +RxNode *RxCompile(const char *Regexp) { + RxNode *n = 0, *x; + if (Regexp == 0) return 0; + RegCount = 0; + n = RxComp(&Regexp); + if (n == 0) return 0; + n = RxOptimize(n); + x = n; + while (x->fNext) x = x->fNext; + x->fNext = NewNode(RE_END); + return n; +} + +void RxFree(RxNode *n) { + RxNode *p; + + while (n) { + p = n; + n = n->fNext; + switch (p->fWhat) { + case RE_INSET: + case RE_NOTINSET: + case RE_CHAR: + free(p->fChar); + break; + default: + break; + } + free(p); + } +} + +#define ChClass(x) (((((x) >= 'A') && ((x) <= 'Z')) || (((x) >= 'a') && ((x) <= 'z')) || (((x) >= '0') && ((x) <= '9')))?1:0) + +static RxMatchRes *match; +static const char *bop; +static const char *eop; +static int flags = RX_CASE; +static const char *rex; + +int RxMatch(RxNode *rx) { + RxNode *n = rx; + + //printf(">>"); + while (n) { + //printf("%-50.50s\n", rex); + //RxDump(1, n); + switch (n->fWhat) { + case RE_NOTHING: + break; + case RE_CASE: + flags |= RX_CASE; + break; + case RE_NCASE: + flags &= ~RX_CASE; + break; + case RE_ATBOL: + if (rex != bop) return 0; + break; + case RE_ATEOL: + if (rex != eop) return 0; + break; + case RE_ANY: + if (rex == eop) return 0; + rex++; + break; + case RE_WSPACE: + if (rex == eop) return 0; + if (*rex != ' ' && *rex != '\n' && *rex != '\r' && *rex != '\t') return 0; + rex++; + break; + case RE_NWSPACE: + if (rex == eop) return 0; + if (*rex == ' ' || *rex == '\n' || *rex == '\r' || *rex == '\t') return 0; + rex++; + break; + case RE_WORD: + if (rex == eop) return 0; + if (!isalnum(*rex)) return 0; + rex++; + break; + case RE_NWORD: + if (rex == eop) return 0; + if (isalnum(*rex)) return 0; + rex++; + break; + case RE_DIGIT: + if (rex == eop) return 0; + if (!isdigit(*rex)) return 0; + rex++; + break; + case RE_NDIGIT: + if (rex == eop) return 0; + if (isdigit(*rex)) return 0; + rex++; + break; + case RE_UPPER: + if (rex == eop) return 0; + if (!isupper(*rex)) return 0; + rex++; + break; + case RE_LOWER: + if (rex == eop) return 0; + if (!islower(*rex)) return 0; + rex++; + break; + case RE_ATBOW: + if (rex >= eop) return 0; + if (rex > bop) { + if ((ChClass(*rex) != 1) || (ChClass(*(rex-1)) != 0)) return 0; + } + break; + case RE_ATEOW: + if (rex <= bop) return 0; + if (rex < eop) { + if ((ChClass(*rex) != 0) || (ChClass(*(rex-1)) != 1)) return 0; + } + break; + case RE_CHAR: + if (rex == eop) return 0; + if (flags & RX_CASE) { + if (*n->fChar != *rex) return 0; + if (memcmp(rex, n->fChar, n->fLen) != 0) return 0; + } else { + for (int i = 0; i < n->fLen; i++) + if (toupper(rex[i]) != toupper(n->fChar[i])) + return 0; + } + rex += n->fLen; + break; + case RE_INSET: + if (rex == eop) return 0; + if ((n->fChar[(unsigned char)(*rex) >> 3] & (1 << ((unsigned char)(*rex) & 7))) == 0) return 0; + rex++; + break; + case RE_NOTINSET: + if (rex == eop) return 0; + if (n->fChar[(unsigned char)(*rex) >> 3] & (1 << ((unsigned char)(*rex) & 7))) return 0; + rex++; + break; + case RE_JUMP: + n = n->fPtr; + continue; + case RE_END: + return 1; + case RE_BREAK: + n = n->fNext; + if (n->fNext == 0) break; + n = n->fNext; + if (n->fWhat & RE_BRANCH) { + while ((n->fWhat & RE_BRANCH) && n->fPtr && ((n->fWhat & 0xFF) == '|')) + n = n->fPtr->fNext; + } + if (n->fWhat & RE_GROUP) { + int C = 1; + n = n->fNext; + while ((C > 0) && n) { + if (n->fWhat & RE_GROUP) { + if (n->fWhat & RE_OPEN) C++; + else C--; + } + if (C == 0) break; + n = n->fNext; + } + } + break; + default: + if (n->fWhat & RE_GROUP) { + if (n->fWhat & RE_MEM) { + const char *save = rex; + int b = n->fWhat & 0xFF; + int fl = flags; + + if (RxMatch(n->fNext) == 0) { + flags = fl; + if (n->fWhat & RE_OPEN) + match->Open[b] = -1; + else + match->Close[b] = -1; + return 0; + } + + if (n->fWhat & RE_OPEN) { + // if (match->Open[b] == -1) + match->Open[b] = (int) (save - bop); + } else { + // if (match->Close[b] == -1) + match->Close[b] = (int) (save - bop); + } + return 1; + } + } else if (n->fWhat & RE_BRANCH) { + const char *save = rex; + int fl = flags; + + if ((n->fWhat & RE_GREEDY) == 0) { + if (RxMatch(n->fPtr) == 1) return 1; + flags = fl; + rex = save; + } else { + if (RxMatch(n->fNext) == 1) return 1; + flags = fl; + rex = save; + n = n->fPtr; + continue; + } + } + break; + } + n = n->fNext; + } + /* NOTREACHED */ + assert(1 == 0 /* internal regexp error */); + return 0; +} + +int RxTry(RxNode *rx, const char *s) { + int fl = flags; + rex = s; + for (int i = 0; i < NSEXPS; i++) + match->Open[i] = match->Close[i] = -1; + if (RxMatch(rx)) { + match->Open[0] = (int) (s - bop); + match->Close[0] = (int) (rex - bop); + return 1; + } + flags = fl; + return 0; +} + +int RxExec(RxNode *Regexp, const char *Data, int Len, const char *Start, RxMatchRes *Match, unsigned int RxOpt) { + char Ch; + if (Regexp == 0) return 0; + + match = Match; + bop = Data; + eop = Data + Len; + + flags = RxOpt; + + for (int i = 0; i < NSEXPS; i++) Match->Open[i] = Match->Close[i] = -1; + + switch (Regexp->fWhat) { // this should be more clever + case RE_ATBOL: // match is anchored + return RxTry(Regexp, Start); + case RE_CHAR: // search for a character to match + Ch = Regexp->fChar[0]; + if (Start == eop) + break; + if (flags & RX_CASE) { + while (1) { + while (Start < eop && *Start != Ch) + Start++; + if (Start == eop) + break; + if (RxTry(Regexp, Start)) + return 1; + if (++Start == eop) + break; + } + } else { + Ch = toupper(Ch); + while (1) { + while (Start < eop && toupper(*Start) != Ch) + Start++; + if (Start == eop) + break; + if (RxTry(Regexp, Start)) + return 1; + if (++Start == eop) + break; + } + } + break; + default: // (slow) + do { + if (RxTry(Regexp, Start)) return 1; + } while (Start++ < eop); + break; + } + return 0; +} + +#define FLAG_UP_CASE 1 +#define FLAG_DOWN_CASE 2 +#define FLAG_UP_NEXT 4 +#define FLAG_DOWN_NEXT 8 + +static int add(int *len, char **s, const char *a, int alen, int &flag) { + int NewLen = *len + alen; + int i; + + NewLen = NewLen * 2; + + if (alen == 0) + return 0; + + if (*s) { + *s = (char *) realloc(*s, NewLen); + assert(*s); + memcpy(*s + *len, a, alen); + } else { + *s = (char *) malloc(NewLen); + assert(*s); + memcpy(*s, a, alen); + *len = 0; + } + if (flag & FLAG_UP_CASE) { + char *p = *s + *len; + + for (i = 0; i < alen; i++) { + *p = (char)toupper(*p); + p++; + } + } else if (flag & FLAG_DOWN_CASE) { + char *p = *s + *len; + + for (i = 0; i < alen; i++) { + *p = (char)tolower(*p); + p++; + } + } + if (flag & FLAG_UP_NEXT) { + char *p = *s + *len; + + *p = (char)toupper(*p); + flag &= ~FLAG_UP_NEXT; + } else if (flag & FLAG_DOWN_NEXT) { + char *p = *s + *len; + + *p = (char)tolower(*p); + flag &= ~FLAG_DOWN_NEXT; + } + *len += alen; + return 0; +} + +int RxReplace(const char *rep, const char *Src, int /*len*/, RxMatchRes match, char **Dest, int *Dlen) { + int dlen = 0; + char *dest = 0; + char Ch; + int n; + int flag = 0; + + *Dest = 0; + *Dlen = 0; + // add(&dlen, &dest, Src, match.Open[0]); + while (*rep) { + switch (Ch = *rep++) { + // case '&': + // add(&dlen, &dest, Src + match.Open[0], match.Close[0] - match.Open[0], flag); + // break; + case '\\': + switch (Ch = *rep++) { + case '0': + case '1': case '2': case '3': + case '4': case '5': case '6': + case '7': case '8': case '9': + n = Ch - 48; + + if (match.Open[n] != -1 && match.Close[n] != -1) { + add(&dlen, &dest, Src + match.Open[n], match.Close[n] - match.Open[n], flag); + } else return -1; + break; + case 0: + if (dest) free(dest); + return -1; // error + case 'r': Ch = '\r'; add(&dlen, &dest, &Ch, 1, flag); break; + case 'n': Ch = '\n'; add(&dlen, &dest, &Ch, 1, flag); break; + case 'b': Ch = '\b'; add(&dlen, &dest, &Ch, 1, flag); break; + case 'a': Ch = '\a'; add(&dlen, &dest, &Ch, 1, flag); break; + case 't': Ch = '\t'; add(&dlen, &dest, &Ch, 1, flag); break; + case 'U': flag |= FLAG_UP_CASE; break; + case 'u': flag |= FLAG_UP_NEXT; break; + case 'L': flag |= FLAG_DOWN_CASE; break; + case 'l': flag |= FLAG_DOWN_NEXT; break; + case 'E': + case 'e': flag &= ~(FLAG_UP_CASE | FLAG_DOWN_CASE); break; + case 'x': + { + int N = 0; + int A = 0; + + if (*rep == 0) { free(dest); return 0; } + N = toupper(*rep) - 48; if (N > 9) N = N + 48 - 65 + 10; if (N > 15) return 0; + rep++; + A = N << 4; + if (*rep == 0) { free(dest); return 0; } + N = toupper(*rep) - 48; if (N > 9) N = N + 48 - 65 + 10; if (N > 15) return 0; + rep++; + A = A + N; + Ch = (char)A; + } + add(&dlen, &dest, &Ch, 1, flag); + break; + case 'd': + { + int N = 0; + int A = 0; + + if (*rep == 0) { free(dest); return 0; } + N = toupper(*rep) - 48; if (N > 9) { free(dest); return 0; } + rep++; + A = N * 100; + if (*rep == 0) { free(dest); return 0; } + N = toupper(*rep) - 48; if (N > 9) { free(dest); return 0; } + rep++; + A = N * 10; + if (*rep == 0) { free(dest); return 0; } + N = toupper(*rep) - 48; if (N > 9) { free(dest); return 0; } + rep++; + A = A + N; + Ch = (char)A; + } + add(&dlen, &dest, &Ch, 1, flag); + break; + case 'o': + { + int N = 0; + int A = 0; + + if (*rep == 0) { free(dest); return 0; } + N = toupper(*rep) - 48; if (N > 7) { free(dest); return 0; } + rep++; + A = N * 64; + if (*rep == 0) { free(dest); return 0; } + N = toupper(*rep) - 48; if (N > 7) { free(dest); return 0; } + rep++; + A = N * 8; + if (*rep == 0) { free(dest); return 0; } + N = toupper(*rep) - 48; if (N > 7) { free(dest); return 0; } + rep++; + A = A + N; + Ch = (char)A; + } + add(&dlen, &dest, &Ch, 1, flag); + break; + default: + add(&dlen, &dest, &Ch, 1, flag); + break; + } + break; + default: + add(&dlen, &dest, &Ch, 1, flag); + break; + } + } + // add(&dlen, &dest, Src + match.Close[0], len - match.Close[0]); + *Dlen = dlen; + *Dest = dest; + return 0; +} + +#ifdef DEBUG + +static void RxDump(int N, RxNode *n) { + while (n) { + for (int i = 0; i < N; i++) printf(" "); + switch (n->fWhat) { + case RE_NOTHING: printf("NOTHING\n"); break; + case RE_CHAR: printf("CHAR '%.1s'\n", n->fChar); break; + case RE_ATBOL: printf("^\n"); break; + case RE_ATEOL: printf("$\n"); break; + case RE_ANY: printf(".\n"); break; + case RE_INSET: printf("[\n"/*, n->fChar*/); break; + case RE_NOTINSET: printf("[^\n"/*, n->fChar*/); break; + case RE_ATBOW: printf("<\n"); break; + case RE_ATEOW: printf(">\n"); break; + case RE_WSPACE: printf("WSPACE\n"); break; + case RE_NWSPACE: printf("NWSPACE\n"); break; + case RE_UPPER: printf("UPPER\n"); break; + case RE_LOWER: printf("LOWER\n"); break; + case RE_JUMP: printf("JUMP\n"); break; + case RE_BREAK: printf("BREAK\n"); break; + case RE_END: printf("END\n"); break; + default: + if (n->fWhat & RE_GROUP) { + if (n->fWhat & RE_MEM) { + if (n->fWhat & RE_OPEN) printf("( %d\n", n->fWhat & 0xFF); + if (n->fWhat & RE_CLOSE) printf(") %d\n", n->fWhat & 0xFF); + } else { + if (n->fWhat & RE_OPEN) printf("{\n"); + if (n->fWhat & RE_CLOSE) printf("}\n"); + } + } else if (n->fWhat & RE_BRANCH) { + if (n->fWhat & RE_GREEDY) { + printf("%c\n", n->fWhat & 0xFF); + } else { + printf("%c\n", n->fWhat & 0xFF); + } + } else { + printf("???????????????\n"); + } + break; + } + n = n->fNext; + } +} + +#define TEST(rc,rx,st) \ + strcpy(line,st); \ + assert((a = RxCompile(rx)) != 0); \ + puts("\n--- " rx " -- " st " -- "); \ + RxDump(0,a);\ + assert(rc == RxExec(a, line, strlen(line), line, &b)); \ + RxFree(a); + +int main() { + RxNode *a; + RxMatchRes b; + char line[1024]; + + TEST(1, "a", "a"); + TEST(0, "b", "a"); + TEST(1, "aaaa", "aaaa"); + TEST(0, "bbbb", "aaaa"); + TEST(1, ".", "a"); + TEST(0, ".", ""); + TEST(1, "a..", "axx"); + TEST(0, "a..", "b.."); + TEST(1, "a?b", "ab"); + TEST(1, "a?b", "xb"); + TEST(0, "a?C", "xb"); + TEST(1, "{aa}?b", "aab"); + TEST(1, "{aa}?b", "xab"); + TEST(0, "{aa}?C", "xxb"); + TEST(1, "^aa", "aa"); + TEST(0, "^aa", "baa"); + TEST(1, "^aa$" ,"aa"); + TEST(0, "^aa$", "baab"); + TEST(1, "a*b", "aaab"); + TEST(0, "a*b", "aaaa"); + TEST(1, "{aa}*b", "aaab"); + TEST(0, "{aa}*b", "aaaa"); + TEST(1, "b+", "bb"); + TEST(1, "b+", "b"); + TEST(0, "b+", "a"); + TEST(1, "^b+$", "b"); + TEST(0, "^b+$", "aba"); + TEST(1, "a|b", " a"); + TEST(1, "a|b", " b"); + TEST(0, "a|b", " c"); + TEST(1, "a|b|c|d|e", " a "); + TEST(1, "a|b|c|d|e", " c "); + TEST(1, "a|b|c|d|e", " e "); + TEST(0, "a|b|c|d|e", " x "); + TEST(1, "{a}|{b}|{c}|{d}|{e}", " a "); + TEST(1, "{a}|{b}|{c}|{d}|{e}", " c "); + TEST(1, "{a}|{b}|{c}|{d}|{e}", " e "); + TEST(0, "{a}|{b}|{c}|{d}|{e}", " x "); + TEST(1, "^xx{alpha}|{beta}xx$", "xxalphaxx"); + TEST(1, "^xx{alpha}|{beta}xx$", "xxbetaxx"); + TEST(1, "[a-z]", "aaa"); + TEST(1, "^{Error}|{Warning}", "Warning search.cpp 35: Conversion may lose significant digits in function AskReplace()"); + TEST(1, "^{Error}|{Warning} (.+)", "Warning search.cpp 35: Conversion may lose significant digits in function AskReplace()"); + TEST(1, "^{Error}|{Warning} ([a-z.]#) ([0-9]#)", "Warning search.cpp 35: Conversion may lose significant digits in function AskReplace()"); + TEST(1, "^{Error}|{Warning} (.+) ([0-9]+): (.*)$", "Warning search.cpp 35: Conversion may lose significant digits in function AskReplace()"); + TEST(1, "^{Error}|{Warning} (.+) ([0-9]+): (.*)$", "Error search.cpp 35: Conversion may lose significant digits in function AskReplace()"); + TEST(1, "^([a-z]+ +)*\\(", "blabla bla bla bla ("); + TEST(1, "^([a-z]+\\s+)+\\(", "blabla bla bla bla ("); + TEST(1, "^([a-z]+\\s*)+\\(", "blabla bla bla bla("); + TEST(1, "^([a-z]+\\s+)+\\(", "blabla bla bla bla ("); + TEST(1, "^([a-z]+\\s*)+\\(", "blabla bla bla bla("); + TEST(1, "^([a-z]# #)*\\(", "blabla bla bla bla ("); + TEST(1, "^([a-z]+ @)@\\(", "blabla bla bla bla ("); + TEST(1, "^[\\x20-\\xFF]+$", "blabla"); + TEST(1, "{a{a{a{a|a}|{a|a}a}a}a|a}", "aaaaaaaaaaaaaaaaa"); + + while (1) { + printf("Regexp: "); fflush(stdout); gets(line); + if (!*line) break; + a = RxCompile(line); RxDump(0, a); + printf("String: "); fflush(stdout); gets(line); + printf("rc = %d\n", RxExec(a, line, strlen(line), line, &b)); + for (int i = 0; i < NSEXPS; i++) { + if (b.Open[i] != -1) { + printf("%d: %d %d\n", i, b.Open[i], b.Close[i]); + } + } + RxFree(a); + } + return 0; +} + +#endif diff --git a/src/e_regex.h b/src/e_regex.h new file mode 100644 index 0000000..7003575 --- /dev/null +++ b/src/e_regex.h @@ -0,0 +1,110 @@ +/* e_regex.h + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#ifndef __REGEX_H +#define __REGEX_H + +/* + * Operator: + * + * ^ Match the beginning of line + * $ Match the end of line + * . Match any character + * [ ] Match characters in set + * [^ ] Match characters not in set + * ? Match previous pattern 0 or 1 times (greedy) + * | Match previous or next pattern + * @ Match previous pattern 0 or more times (non-greedy) + * # Match previous pattern 1 or more times (non-greedy) + * * Match previous pattern 0 or more times (greedy) + * + Match previous pattern 1 or more times (greedy) + * { } Group characters to form one pattern + * ( ) Group and remember + * \ Quote next character (only of not a-z) + * < Match beginning of a word + * > Match end of a word + * \x## Match character with ASCII code ## (hex) + * \N### Match ascii code ### (dec) + * \o### Match ascii code + * \a Match \a \r Match 0x13 (cr) + * \b Match \b \t Match 0x09 (tab) + * \f Match \f \v Match \v + * \n Match 0x10 (lf) \e Match escape (^E) + * \s Match whitespace (cr/lf/tab/space) + * \S Match nonwhitespace (!\S) + * \w Match word character + * \W Match non-word character + * \d Match digit character + * \D Match non-digit character + * \U Match uppercase + * \L Match lowercase + * \C Match case sensitively from here on + * \c Match case ingnore from here on + */ + +#define RE_NOTHING 0 // nothing +#define RE_JUMP 1 // jump to +#define RE_BREAK 2 // break | +#define RE_ATBOL 3 // match at beginning of line +#define RE_ATEOL 4 // match at end of line +#define RE_ATBOW 5 // match beginning of word +#define RE_ATEOW 6 // match end of word +#define RE_CASE 7 // match case sensitively from here +#define RE_NCASE 8 // ignore case from here. +#define RE_END 31 // end of regexp + +#define RE_ANY (32 + 1) // match any character +#define RE_INSET (32 + 2) // match if in set +#define RE_NOTINSET (32 + 3) // match if not in set +#define RE_CHAR (32 + 4) // match character string +#define RE_WSPACE (32 + 5) // match whitespace +#define RE_NWSPACE (32 + 6) // match whitespace +#define RE_UPPER (32 + 7) // match uppercase +#define RE_LOWER (32 + 8) // match lowercase +#define RE_DIGIT (32 + 9) // match digit +#define RE_NDIGIT (32 + 10) // match non-digit +#define RE_WORD (32 + 11) // match word +#define RE_NWORD (32 + 12) // match non-word + +#define RE_GROUP 256 // grouping +#define RE_OPEN 512 // open ( +#define RE_CLOSE 1024 // close ) +#define RE_MEM 2048 // store () match + +#define RE_BRANCH 4096 +#define RE_GREEDY 2048 // do a greedy match (as much as possible) + +#define NSEXPS 64 // for replace only 0-9 + +#define RX_CASE 1 // matchcase + +typedef struct _RxNode RxNode; + +struct _RxNode { + short fWhat; + short fLen; + RxNode *fPrev; + RxNode *fNext; + union { + char *fChar; + RxNode *fPtr; + }; +}; + +typedef struct { + int Open[NSEXPS]; // -1 = not matched + int Close[NSEXPS]; +} RxMatchRes; + +RxNode *RxCompile(const char *Regexp); +int RxExec(RxNode *Regexp, const char *Data, int Len, const char *Start, RxMatchRes *Match, unsigned int RxOpt = RX_CASE); +int RxReplace(const char *rep, const char *Src, int len, RxMatchRes match, char **Dest, int *Dlen); +void RxFree(RxNode *Node); + +#endif diff --git a/src/e_search.cpp b/src/e_search.cpp new file mode 100644 index 0000000..e7cac36 --- /dev/null +++ b/src/e_search.cpp @@ -0,0 +1,1153 @@ +/* e_search.cpp + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#include "fte.h" + +int ParseSearchOption(int replace, char c, unsigned long &opt) { + switch (c) { + case 'a': opt |= SEARCH_ALL; break; // search all occurances + case 'b': opt |= SEARCH_BLOCK; break; // search in block only + case 'c': opt &= ~SEARCH_NEXT; break; // search from current position + case 'd': opt |= SEARCH_DELETE; break; // delete found line + case 'g': opt |= SEARCH_GLOBAL; break; // search globally + case 'i': opt |= SEARCH_NCASE; break; // don't match case + case 'j': opt |= SEARCH_JOIN; break; // join found line + case 'r': opt |= SEARCH_BACK; break; // search reverse + case 'w': opt |= SEARCH_WORDBEG | SEARCH_WORDEND; break; + case '<': opt |= SEARCH_WORDBEG; break; + case '>': opt |= SEARCH_WORDEND; break; + case 'x': opt |= SEARCH_RE; break; // search using regexps + default: + if (!replace) return 0; + switch (c) { + case 'n': opt |= SEARCH_NASK; break; // don't ask before replacing + default: + return 0; + } + } + return 1; +} + +int UnquoteString(char *str) { + char *s, *d; + + s = str; + d = str; + while (*s) { + if (*s == '\\') { + s++; + if (*s == 0) return 0; + } + *d++ = *s++; + } + *d = 0; + return 1; +} + +int ParseSearchOptions(int replace, const char *str, unsigned long &Options) { + const char *p = str; + + Options = SEARCH_NEXT; + while (*p) { + if (ParseSearchOption(replace, *p, Options) == 0) return 0; + p++; + } + return 1; +} + +int ParseSearchReplace(EBuffer *B, const char *str, int replace, SearchReplaceOptions &opt) { + int where = 0; + int len = 0; + const char *p = str; + + memset((void *)&opt, 0, sizeof(opt)); + if (p == 0) return 0; + if (replace) { + if (ParseSearchOptions(replace, BFS(B, BFS_DefFindReplaceOpt), opt.Options) == 0) return 0; + opt.Options |= SEARCH_REPLACE; + } else { + if (ParseSearchOptions(replace, BFS(B, BFS_DefFindOpt), opt.Options) == 0) return 0; + } + + while (*p) { + switch (*p) { + case '\\': + if (where == 0) { + opt.strSearch[len++] = *p++; + if (*p == 0) return 0; + opt.strSearch[len++] = *p++; + } else if (where == 1) { + opt.strReplace[len++] = *p++; + if (*p == 0) return 0; + opt.strReplace[len++] = *p++; + } else + return 0; + break; + case '/': + where++; + if (!replace && where == 1) where++; + if (where == 2) + opt.Options = SEARCH_NEXT; + if (where > 2) return 0; + len = 0; + p++; + break; + default: + if (where == 0) + opt.strSearch[len++] = *p++; + else if (where == 1) + opt.strReplace[len++] = *p++; + else { + char c = *p; + + p++; + if (ParseSearchOption(replace, c, opt.Options) == 0) return 0; + } + } + } + if (opt.Options & SEARCH_RE); + else { + if (UnquoteString(opt.strSearch) == 0) return 0; + if (opt.Options & SEARCH_REPLACE) + if (UnquoteString(opt.strReplace) == 0) return 0; + } + + opt.ok = 1; + return 1; +} + +int EBuffer::FindStr(char *Data, int Len, int Options) { + int LLen, Start, End; + int C, L; + PELine X; + char *P; + + if (Options & SEARCH_RE) + return 0; + if (Len <= 0) + return 0; + + if (Options & SEARCH_NOPOS) { + C = Match.Col; + L = Match.Row; + } else { + C = CP.Col; + L = VToR(CP.Row); + } + if (Match.Row != -1) + Draw(Match.Row, Match.Row); + Match.Row = -1; + Match.Col = -1; + X = RLine(L); + C = CharOffset(X, C); + + if (Options & SEARCH_NEXT) { + int CC = MatchCount ? MatchCount : 1; + + if (Options & SEARCH_BACK) { + C -= CC; + if (C < 0) { + if (L == 0) return 0; + L--; + X = RLine(L); + C = X->Count; + } + } else { + C += CC; + if (C >= X->Count) { + C = 0; + L++; + if (L == RCount) return 0; + } + } + } + MatchLen = 0; + MatchCount = 0; + + if (Options & SEARCH_BLOCK) { + if (Options & SEARCH_BACK) { + if (BlockMode == bmStream) { + if (L > BE.Row) { + L = BE.Row; + C = BE.Col; + } + if (L == BE.Row && C > BE.Col) + C = BE.Col; + } else { + if (L >= BE.Row && BE.Row > 0) { + L = BE.Row - 1; + C = RLine(L)->Count; + } + if (BlockMode == bmColumn) + if (L == BE.Row - 1 && C >= BE.Col) + C = BE.Col; + } + } else { + if (L < BB.Row) { + L = BB.Row; + C = 0; + } + if (L == BB.Row && C < BB.Col) + C = BB.Col; + } + } + while (1) { + if (Options & SEARCH_BLOCK) { + if (BlockMode == bmStream) { + if (L > BE.Row || L < BB.Row) break; + } else + if (L >= BE.Row || L < BB.Row) break; + } else + if (L >= RCount || L < 0) break; + + X = RLine(L); + + LLen = X->Count; + P = X->Chars; + Start = 0; + End = LLen; + + if (Options & SEARCH_BLOCK) { + if (BlockMode == bmColumn) { + Start = CharOffset(X, BB.Col); + End = CharOffset(X, BE.Col); + } else if (BlockMode == bmStream) { + if (L == BB.Row) + Start = CharOffset(X, BB.Col); + if (L == BE.Row) + End = CharOffset(X, BE.Col); + } + } + if (Options & SEARCH_BACK) { + if (C >= End - Len) + C = End - Len; + } else { + if (C < Start) + C = Start; + } + + while (((!(Options & SEARCH_BACK)) && (C <= End - Len)) || ((Options & SEARCH_BACK) && (C >= Start))) { + if ((!(Options & SEARCH_WORDBEG) + || (C == 0) + || (WGETBIT(Flags.WordChars, P[C - 1]) == 0)) + && + (!(Options & SEARCH_WORDEND) + || (C + Len >= End) + || (WGETBIT(Flags.WordChars, P[C + Len]) == 0)) + && + ((!(Options & SEARCH_NCASE) + && (P[C] == Data[0]) + && (memcmp(P + C, Data, Len) == 0)) + || + ((Options & SEARCH_NCASE) + && (toupper(P[C]) == toupper(Data[0])) + && (strnicmp(P + C, Data, Len) == 0))) /* && BOL | EOL */ + ) + { + Match.Col = ScreenPos(X, C); + Match.Row = L; + MatchCount = Len; + MatchLen = ScreenPos(X, C + Len) - Match.Col; + if (!(Options & SEARCH_NOPOS)) { + if (Options & SEARCH_CENTER) + CenterPosR(Match.Col, Match.Row); + else + SetPosR(Match.Col, Match.Row); + } + Draw(L, L); + return 1; + } + if (Options & SEARCH_BACK) C--; else C++; + } + if (Options & SEARCH_BACK) { + L--; + if (L >= 0) + C = RLine(L)->Count; + } else { + C = 0; + L++; + } + } + //SetPos(OC, OL); + return 0; +} + +int EBuffer::FindRx(RxNode *Rx, int Options) { + int LLen, Start, End; + int C, L; + char *P; + PELine X; + RxMatchRes b; + + if (!(Options & SEARCH_RE)) + return 0; + if (Options & SEARCH_BACK) { // not supported + View->MView->Win->Choice(GPC_ERROR, "FindRx", 1, "O&K", "Reverse regexp search not supported."); + return 0; + } + if (Rx == 0) + return 0; + + if (Match.Row != -1) + Draw(Match.Row, Match.Row); + Match.Row = -1; + Match.Col = -1; + + C = CP.Col; + L = VToR(CP.Row); + X = RLine(L); + C = CharOffset(X, C); + + if (Options & SEARCH_NEXT) { + int CC = MatchCount ? MatchCount : 1; + + if (Options & SEARCH_BACK) { + C -= CC; + if (Options & SEARCH_BLOCK) { + if (C < BB.Col && L == BB.Row) + return 0; + L--; + X = RLine(L); + C = X->Count; + if (BlockMode == bmColumn) + if (BE.Col < C) + C = BE.Col; + } else { + if (C < 0 && L == 0) + return 0; + L--; + X = RLine(L); + C = X->Count; + } + } else { + C += CC; + if (Options & SEARCH_BLOCK) { + if (BlockMode == bmStream || BlockMode == bmLine) { + if (C >= X->Count) { + C = 0; + L++; + if (BlockMode == bmLine) { + if (L == BE.Row) return 0; + } else + if (L == BE.Row && (C >= BE.Col || C >= X->Count)) + return 0; + } + } else if (BlockMode == bmColumn) { + if (C >= X->Count || C >= BE.Col) { + C = BB.Col; + L++; + if (L == BE.Row) return 0; + } + } + } else { + if (C >= X->Count) { + C = 0; + L++; + if (L == RCount) return 0; + } + } + } + } + MatchLen = 0; + MatchCount = 0; + + if (Options & SEARCH_BLOCK) { + if (Options & SEARCH_BACK) { + if (BlockMode == bmStream) { + if (L > BE.Row) { + L = BE.Row; + C = BE.Col; + } + if (L == BE.Row && C > BE.Col) + C = BE.Col; + } else { + if (L >= BE.Row && BE.Row > 0) { + L = BE.Row - 1; + C = RLine(L)->Count; + } + if (BlockMode == bmColumn) + if (L == BE.Row - 1 && C >= BE.Col) + C = BE.Col; + } + } else { + if (L < BB.Row) { + L = BB.Row; + C = 0; + } + if (L == BB.Row && C < BB.Col) + C = BB.Col; + } + } + + while (1) { + if (Options & SEARCH_BLOCK) { + if (BlockMode == bmStream) { + if (L > BE.Row || L < BB.Row) break; + } else + if (L >= BE.Row || L < BB.Row) break; + } else + if (L >= RCount || L < 0) break; + + X = RLine(L); + LLen = X->Count; + P = X->Chars; + Start = 0; + End = LLen; + + if (Options & SEARCH_BLOCK) { + if (BlockMode == bmColumn) { + Start = CharOffset(X, BB.Col); + End = CharOffset(X, BE.Col); + } else if (BlockMode == bmStream) { + if (L == BB.Row) + Start = CharOffset(X, BB.Col); + if (L == BE.Row) + End = CharOffset(X, BE.Col); + } + if (End > LLen) + End = LLen; + } + if (Options & SEARCH_BACK) { + if (C >= End) + C = End; + } else { + if (C < Start) + C = Start; + } + + if (Start <= End) { + if (RxExec(Rx, P + Start, End - Start, P + C, &b, (Options & SEARCH_NCASE) ? 0 : RX_CASE) == 1) { + C = ScreenPos(X, b.Open[0] + Start); + Match.Col = C; + Match.Row = L; + MatchCount = b.Close[0] - b.Open[0]; + MatchLen = ScreenPos(X, b.Close[0] + Start) - C; + for (int mm = 0; mm < NSEXPS; mm++) { + b.Open[mm] += Start; + b.Close[mm] += Start; + } + MatchRes = b; + if (!(Options & SEARCH_NOPOS)) { + if (Options & SEARCH_CENTER) + CenterPosR(C, L); + else + SetPosR(C, L); + } + Draw(L, L); + return 1; + } + } + C = 0; + L++; + } + //SetPos(OC, OL); + return 0; + +} + +int EBuffer::Find(SearchReplaceOptions &opt) { + int slen = strlen(opt.strSearch); + int Options = opt.Options; + int rlen = strlen(opt.strReplace); + RxNode *R = NULL; + + opt.resCount = -1; + + if (slen == 0) return 0; + if (Options & SEARCH_BLOCK) { + if (CheckBlock() == 0) return 0; + } + if (Options & SEARCH_RE) { + R = RxCompile(opt.strSearch); + if (R == 0) { + View->MView->Win->Choice(GPC_ERROR, "Find", 1, "O&K", "Invalid regular expression."); + return 0; + } + } + if (Options & SEARCH_GLOBAL) { + if (Options & SEARCH_BLOCK) { + if (Options & SEARCH_BACK) { + if (SetPosR(BE.Col, BE.Row) == 0) goto error; + } else { + if (SetPosR(BB.Col, BB.Row) == 0) goto error; + } + } else { + if (Options & SEARCH_BACK) { + if (RCount < 1) goto error; + if (SetPosR(LineLen(RCount - 1), RCount - 1) == 0) goto error; + } else { + if (SetPosR(0, 0) == 0) goto error; + } + } + } + opt.resCount = 0; + while (1) { + if (Options & SEARCH_RE) { + if (FindRx(R, Options) == 0) goto end; + } else { + if (FindStr(opt.strSearch, slen, Options) == 0) goto end; + } + opt.resCount++; + + if (opt.Options & SEARCH_REPLACE) { + char ask = 'A'; + + if (!(Options & SEARCH_NASK)) { + char ch; + + while (1) { + Draw(VToR(CP.Row), 1); + Redraw(); + switch (View->MView->Win->Choice(0, "Replace", + 5, + "&Yes", + "&All", + "&Once", + "&Skip", + "&Cancel", + "Replace with %s?", opt.strReplace)) + { + case 0: ch = 'Y'; break; + case 1: ch = 'A'; break; + case 2: ch = 'O'; break; + case 3: ch = 'N'; break; + case 4: + case -1: + default: + ch = 'Q'; break; + } + if (ch == 'Y') { ask = 'Y'; goto ok_rep; } + if (ch == 'N') { ask = 'N'; goto ok_rep; } + if (ch == 'Q') { ask = 'Q'; goto ok_rep; } + if (ch == 'A') { ask = 'A'; goto ok_rep; } + if (ch == 'O') { ask = 'O'; goto ok_rep; } + } + ok_rep: + if (ask == 'N') goto try_join; + if (ask == 'Q') goto end; + if (ask == 'A') Options |= SEARCH_NASK; + } + + if (Options & SEARCH_RE) { + PELine L = RLine(Match.Row); + int P, R; + char *PR = 0; + int LR = 0; + + R = Match.Row; + P = Match.Col; + P = CharOffset(L, P); + + if (0 == RxReplace(opt.strReplace, L->Chars, L->Count, MatchRes, &PR, &LR)) { + if (DelText(R, Match.Col, MatchLen) == 0) goto error; + if (PR && LR > 0) + if (InsText(R, Match.Col, LR, PR) == 0) goto error; + if (PR) + free(PR); + rlen = LR; + } + } else { + if (DelText(Match.Row, Match.Col, MatchLen) == 0) goto error; + if (InsText(Match.Row, Match.Col, rlen, opt.strReplace) == 0) goto error; + } + if (!(Options & SEARCH_BACK)) { + MatchLen = rlen; + MatchCount = rlen; + } + if (ask == 'O') + goto end; + } + try_join: + if (Options & SEARCH_JOIN) { + char ask = 'A'; + + if (!(Options & SEARCH_NASK)) { + char ch; + + while (1) { + Draw(VToR(CP.Row), 1); + Redraw(); + switch (View->MView->Win->Choice(0, "Join Line", + 5, + "&Yes", + "&All", + "&Once", + "&Skip", + "&Cancel", + "Join lines %d and %d?", 1 + VToR(CP.Row), 1 + VToR(CP.Row) + 1)) + { + case 0: ch = 'Y'; break; + case 1: ch = 'A'; break; + case 2: ch = 'O'; break; + case 3: ch = 'N'; break; + case 4: + case -1: + default: + ch = 'Q'; break; + } + if (ch == 'Y') { ask = 'Y'; goto ok_join; } + if (ch == 'N') { ask = 'N'; goto ok_join; } + if (ch == 'Q') { ask = 'Q'; goto ok_join; } + if (ch == 'A') { ask = 'A'; goto ok_join; } + if (ch == 'O') { ask = 'O'; goto ok_join; } + } + ok_join: + if (ask == 'N') goto try_delete; + if (ask == 'Q') goto end; + if (ask == 'A') Options |= SEARCH_NASK; + } + + if (JoinLine(Match.Row, Match.Col) == 0) goto error; + + if (ask == 'O') + goto end; + } + try_delete: + if (Options & SEARCH_DELETE) { + char ask = 'A'; + + if (!(Options & SEARCH_NASK)) { + char ch; + + while (1) { + Draw(VToR(CP.Row), 1); + Redraw(); + switch (View->MView->Win->Choice(0, "Delete Line", + 5, + "&Yes", + "&All", + "&Once", + "&Skip", + "&Cancel", + "Delete line %d?", VToR(CP.Row))) + { + case 0: ch = 'Y'; break; + case 1: ch = 'A'; break; + case 2: ch = 'O'; break; + case 3: ch = 'N'; break; + case 4: + case -1: + default: + ch = 'Q'; break; + } + if (ch == 'Y') { ask = 'Y'; goto ok_delete; } + if (ch == 'N') { ask = 'N'; goto ok_delete; } + if (ch == 'Q') { ask = 'Q'; goto ok_delete; } + if (ch == 'A') { ask = 'A'; goto ok_delete; } + if (ch == 'O') { ask = 'O'; goto ok_delete; } + } + ok_delete: + if (ask == 'N') goto next; + if (ask == 'Q') goto end; + if (ask == 'A') Options |= SEARCH_NASK; + } + + if (Match.Row == RCount - 1) { + if (DelText(Match.Row, 0, LineLen()) == 0) goto error; + } else + if (DelLine(Match.Row) == 0) goto error; + + if (ask == 'O') + goto end; + if (!(Options & SEARCH_ALL)) + break; + goto last; + } + next: + if (!(Options & SEARCH_ALL)) + break; + Options |= SEARCH_NEXT; + last: + ; + } +end: + // end of search + if (R) + RxFree(R); + + if (Options & SEARCH_ALL) + Msg(S_INFO, "%d match(es) found.", opt.resCount); + else { + if (opt.resCount == 0) { + Msg(S_INFO, "[%s] not found", opt.strSearch); + return 0; + } + } + return 1; +error: + + if (R) + { + RxFree(R); + } + View->MView->Win->Choice(GPC_ERROR, "Find", 1, "O&K", "Error in search/replace."); + return 0; +} + + +int EBuffer::CompleteWord() { +#ifdef CONFIG_I_COMPLETE + return View->MView->Win->ICompleteWord(View); +#else + PELine L = VLine(CP.Row), M; + int C, P, X, P1, N, xlen, XL; + EPoint O = CP; + + if (CP.Col == 0) return 0; + + if (SetPos(CP.Col, CP.Row) == 0) return 0; + + C = CP.Col; + P = CharOffset(L, C); + P1 = P; + N = VToR(CP.Row); + + if (P > L->Count) return 0; + + if (P > 0) { + while ((P > 0) && ((ChClass(L->Chars[P - 1]) == 1) || (L->Chars[P - 1] == '_'))) P--; + if (P == P1) return 0; + xlen = P1 - P; + C = ScreenPos(L, P); + Match.Row = N; + Match.Col = C; + //if (SetPos(C, CP.Row) == 0) return 0; + //again: + if (FindStr(L->Chars + P, xlen, SEARCH_BACK | SEARCH_NEXT | SEARCH_NOPOS | SEARCH_WORDBEG) == 1) { + M = RLine(Match.Row); + X = CharOffset(M, Match.Col); + XL = X; + //if ((XL > 0) && ((ChClass(M->Chars[XL - 1]) == 1) || (M->Chars[XL - 1] == '_'))) goto again; + while ((XL < M->Count) && ((ChClass(M->Chars[XL]) == 1) || (M->Chars[XL] == '_'))) XL++; + { + char *pp = (char *)malloc(XL - X - xlen); + + if (pp) { + memcpy(pp, M->Chars + X + xlen, XL - X - xlen); + + if (InsText(N, O.Col, + XL - X - xlen, + pp, + 1) == 0) return 0; + free(pp); + } + } + if (SetPos(O.Col + XL - X - xlen, O.Row) == 0) return 0; + Draw(Match.Row, Match.Row); + Match.Row = -1; + Match.Col = -1; + MatchLen = 0; + MatchCount = 0; + return 1; + } + } + if (Match.Row != -1) + Draw(Match.Row, Match.Row); + Match.Col = Match.Row = -1; + MatchLen = 0; + MatchCount = 0; + return 0; +#endif +} + +int EBuffer::Search(ExState &State, char *aString, int Options, int /*CanResume*/) { + char find[MAXSEARCH+1] = ""; + int Case = BFI(this, BFI_MatchCase) ? 0 : SEARCH_NCASE; + int Next = 0; + int erc = 0; + //int Changed; + + if (aString) + strcpy(find, aString); + else + if (State.GetStrParam(View, find, sizeof(find)) == 0) + if ((erc = View->MView->Win->GetStr("Find", sizeof(find), find, HIST_SEARCH)) == 0) return 0; + if (strlen(find) == 0) return 0; + + if (erc == 2) + Case ^= SEARCH_NCASE; + + //if (Changed == 0 && CanResume) + // Next |= SEARCH_NEXT; + + LSearch.ok = 0; + strcpy(LSearch.strSearch, find); + LSearch.Options = Case | Next | (Options & ~SEARCH_NCASE); + LSearch.ok = 1; + if (Find(LSearch) == 0) return 0; + return 1; +} + +int EBuffer::SearchAgain(ExState &/*State*/, unsigned int Options) { + if (LSearch.ok == 0) return 0; + LSearch.Options |= SEARCH_NEXT; + if ((Options & SEARCH_BACK) != (LSearch.Options & SEARCH_BACK)) + LSearch.Options ^= SEARCH_BACK; + if (Find(LSearch) == 0) return 0; + return 1; +} + +int EBuffer::SearchReplace(ExState &State, char *aString, char *aReplaceString, int Options) { + char find[MAXSEARCH+1] = ""; + char replace[MAXSEARCH+1] = ""; + int Case = BFI(this, BFI_MatchCase) ? 0 : SEARCH_NCASE; + + if (aString) + strcpy(find, aString); + else + if (State.GetStrParam(View, find, sizeof(find)) == 0) + if (View->MView->Win->GetStr("Find", sizeof(find), find, HIST_SEARCH) == 0) return 0; + if (strlen(find) == 0) return 0; + if (aReplaceString) + strcpy(replace, aReplaceString); + else + if (State.GetStrParam(View, replace, sizeof(replace)) == 0) + if (View->MView->Win->GetStr("Replace", sizeof(replace), replace, HIST_SEARCH) == 0) return 0; + + LSearch.ok = 0; + strcpy(LSearch.strSearch, find); + strcpy(LSearch.strReplace, replace); + LSearch.Options = Case | (Options & ~SEARCH_NCASE) | SEARCH_ALL | SEARCH_REPLACE; + LSearch.ok = 1; + if (Find(LSearch) == 0) return 0; + return 1; +} + +int EBuffer::Search(ExState &State) { return Search(State, 0, 0, 1); } +int EBuffer::SearchB(ExState &State) { return Search(State, 0, SEARCH_BACK, 1); } +int EBuffer::SearchRx(ExState &State) { return Search(State, 0, SEARCH_RE, 1); } +int EBuffer::SearchAgain(ExState &State) { return SearchAgain(State, 0); } +int EBuffer::SearchAgainB(ExState &State) { return SearchAgain(State, SEARCH_BACK); } +int EBuffer::SearchReplace(ExState &State) { return SearchReplace(State, 0, 0, 0); } +int EBuffer::SearchReplaceB(ExState &State) { return SearchReplace(State, 0, 0, SEARCH_BACK); } +int EBuffer::SearchReplaceRx(ExState &State) { return SearchReplace(State, 0, 0, SEARCH_RE); } + +#ifdef CONFIG_OBJ_ROUTINE +int EBuffer::ScanForRoutines() { + RxNode *regx; + int line; + PELine L; + RxMatchRes res; + + if (BFS(this, BFS_RoutineRegexp) == 0) { + View->MView->Win->Choice(GPC_ERROR, "Error", 1, "O&K", "No routine regexp."); + return 0; + } + regx = RxCompile(BFS(this, BFS_RoutineRegexp)); + if (regx == 0) { + View->MView->Win->Choice(GPC_ERROR, "Error", 1, "O&K", "Failed to compile regexp '%s'", BFS(this, BFS_RoutineRegexp)); + return 0; + } + + if (rlst.Lines) { + free(rlst.Lines); + rlst.Lines = 0; + } + rlst.Lines = 0; + rlst.Count = 0; + + Msg(S_BUSY, "Matching %s", BFS(this, BFS_RoutineRegexp)); + for (line = 0; line < RCount; line++) { + L = RLine(line); + if (RxExec(regx, L->Chars, L->Count, L->Chars, &res) == 1) { + rlst.Count++; + rlst.Lines = (int *) realloc((void *) rlst.Lines, sizeof(int) * (rlst.Count | 0x1F)); + rlst.Lines[rlst.Count - 1] = line; + Msg(S_BUSY, "Routines: %d", rlst.Count); + } + } + RxFree(regx); + return 1; +} +#endif + +int EBuffer::ShowPosition() { + int CLine, NLines; + int CAct, NAct; + int CColumn, NColumns; + int CCharPos, NChars; +#ifdef HEAPWALK + unsigned long MemUsed = 0, MemFree = 0, BlkUsed = 0, BlkFree = 0, BigFree = 0, BigUsed = 0; +#endif + + if (!View) + return 0; + + CLine = CP.Row + 1; + NLines = VCount; + CAct = VToR(CP.Row) + 1; + NAct = RCount; + CColumn = CP.Col + 1; + NColumns = LineLen(CP.Row); + CCharPos = CharOffset(VLine(CP.Row), CP.Col) + 1; + NChars = VLine(CP.Row)->Count; + +#ifdef HEAPWALK + if (_heapchk() != _HEAPOK) { + MemUsed = -1; + } else { + _HEAPINFO hi; + + hi._pentry = NULL; + while (_heapwalk(&hi) == _HEAPOK) { + if (hi._useflag == _USEDENTRY) { + BlkUsed++; + MemUsed += hi._size; + if (hi._size > BigUsed) + BigUsed = hi._size; + //fprintf(stderr, "USED %d\n", hi._size); + } else { + BlkFree++; + MemFree += hi._size; + if (hi._size > BigFree) + BigFree = hi._size; + //fprintf(stderr, "FREE %d\n", hi._size); + } + } + } +#endif + +#ifdef CONFIG_UNDOREDO + int NN = -1; + if (US.UndoPtr > 0) + NN = US.Top[US.UndoPtr - 1]; +#endif + Msg(S_INFO, +#ifdef HEAPWALK + "M%ld,%ld B%ld,%ld S%ld,%ld" +#endif + "L%d/%d G%d/%d/%d A%d/%d C%d/%d P%d/%d " +#ifdef CONFIG_UNDOREDO + "U%d/%d/%d " +#endif + "H%d/%d/%d", +#ifdef HEAPWALK + MemUsed, MemFree, BlkUsed, BlkFree, BigUsed, BigFree, +#endif + CLine, NLines, + RGap, RCount, RAllocated, + CAct, NAct, + CColumn, NColumns, + CCharPos, NChars, +#ifdef CONFIG_UNDOREDO + US.UndoPtr, US.Num, NN, +#endif + StartHilit, MinRedraw, MaxRedraw); + return 1; +} + +#ifdef CONFIG_BOOKMARKS +int EBuffer::PlaceBookmark(char *Name, EPoint P) { + int i; + EBookmark *p; + + assert(P.Row >= 0 && P.Row < RCount && P.Col >= 0); + + for (i = 0; i < BMCount; i++) { + if (strcmp(Name, BMarks[i].Name) == 0) { + BMarks[i].BM = P; + return 1; + } + } + p = (EBookmark *) realloc(BMarks, sizeof (EBookmark) * (1 + BMCount)); + if (p == 0) return 0; + BMarks = p; + BMarks[BMCount].Name = strdup(Name); + BMarks[BMCount].BM = P; + BMCount++; + return 1; +} + +int EBuffer::RemoveBookmark(char *Name) { + int i; + + for (i = 0; i < BMCount; i++) { + if (strcmp(Name, BMarks[i].Name) == 0) { + free(BMarks[i].Name); + memmove(BMarks + i, BMarks + i + 1, sizeof(EBookmark) * (BMCount - i - 1)); + BMCount--; + BMarks = (EBookmark *) realloc(BMarks, sizeof (EBookmark) * BMCount); + return 1; + } + } + View->MView->Win->Choice(GPC_ERROR, "RemoveBookmark", 1, "O&K", "Bookmark %s not found.", Name); + return 0; +} + +int EBuffer::GetBookmark(char *Name, EPoint &P) { + for (int i = 0; i < BMCount; i++) + if (strcmp(Name, BMarks[i].Name) == 0) { + P = BMarks[i].BM; + return 1; + } + return 0; +} + +int EBuffer::GotoBookmark(char *Name) { + for (int i = 0; i < BMCount; i++) + if (strcmp(Name, BMarks[i].Name) == 0) { + return CenterNearPosR(BMarks[i].BM.Col, BMarks[i].BM.Row); + } + View->MView->Win->Choice(GPC_ERROR, "GotoBookmark", 1, "O&K", "Bookmark %s not found.", Name); + return 0; +} +#endif + +int EBuffer::GetMatchBrace(EPoint &M, int MinLine, int MaxLine, int show) { + int StateLen; + hsState *StateMap = 0; + int Pos; + PELine L = VLine(M.Row); + int dir = 0; + hsState State; + char Ch1, Ch2; + int CountX = 0; + int StateRow = -1; + + M.Row = VToR(CP.Row); + + Pos = CharOffset(L, M.Col); + if (Pos >= L->Count) return 0; + switch(L->Chars[Pos]) { + case '{': dir = +1; Ch1 = '{'; Ch2 = '}'; break; + case '[': dir = +1; Ch1 = '['; Ch2 = ']'; break; + case '<': dir = +1; Ch1 = '<'; Ch2 = '>'; break; + case '(': dir = +1; Ch1 = '('; Ch2 = ')'; break; + case '}': dir = -1; Ch1 = '}'; Ch2 = '{'; break; + case ']': dir = -1; Ch1 = ']'; Ch2 = '['; break; + case '>': dir = -1; Ch1 = '>'; Ch2 = '<'; break; + case ')': dir = -1; Ch1 = ')'; Ch2 = '('; break; + default: + return 0; + } + StateMap = 0; + if (GetMap(M.Row, &StateLen, &StateMap) == 0) return 0; + State = StateMap[Pos]; + StateRow = M.Row; + + while (M.Row >= MinLine && M.Row < MaxLine) { + while (Pos >= 0 && Pos < L->Count) { + if (L->Chars[Pos] == Ch1 || L->Chars[Pos] == Ch2) { + // update syntax state if needed + if (StateRow != M.Row) { + free(StateMap); + StateMap = 0; + GetMap(M.Row, &StateLen, &StateMap); + if (StateMap == 0) return 0; + StateRow = M.Row; + } + if (StateMap[Pos] == State) { + if (L->Chars[Pos] == Ch1) CountX++; + if (L->Chars[Pos] == Ch2) CountX--; + if (CountX == 0) { + M.Col = ScreenPos(L, Pos); + free(StateMap); + return 1; + } + } + } + Pos += dir; + } + M.Row += dir; + if (M.Row >= 0 && M.Row < RCount) { + L = RLine(M.Row); + Pos = (dir == 1) ? 0 : (L->Count - 1); + } + } + if (StateMap) free(StateMap); + if (show) + Msg(S_INFO, "No match (%d missing).", CountX); + return 0; +} + +int EBuffer::MatchBracket() { + EPoint M = CP; + + if (GetMatchBrace(M, 0, RCount, 1) == 1) + return SetPosR(M.Col, M.Row); + return 0; +} + +int EBuffer::HilitMatchBracket() { + EPoint M = CP; + + if (View == 0) + return 0; + + int Min = VToR(GetVPort()->TP.Row); + int Max = VToR(GetVPort()->TP.Row); + Max += GetVPort()->Rows; + if (Max >= RCount) + Max = RCount; + if (Min < 0) + Min = 0; + if (Max < Min) + return 0; + if (GetMatchBrace(M, Min, Max, 0) == 1) { + Match = M; + MatchLen = 1; + MatchCount = 1; + Draw(Match.Row, Match.Row); + return 1; + } + return 0; +} + +int EBuffer::SearchWord(int SearchFlags) { + char word[MAXSEARCH + 1]; + PELine L = VLine(CP.Row); + int P, len = 0; + int Case = BFI(this, BFI_MatchCase) ? 0 : SEARCH_NCASE; + + P = CharOffset(L, CP.Col); + while ((P > 0) && ((ChClass(L->Chars[P - 1]) == 1) || (L->Chars[P - 1] == '_'))) + P--; + while (len < int(sizeof(word)) && P < L->Count && (ChClass(L->Chars[P]) == 1 || L->Chars[P] == '_')) + word[len++] = L->Chars[P++]; + word[len] = 0; + if (len == 0) + return 0; + + return FindStr(word, len, Case | SearchFlags | SEARCH_WORD); +} + +int EBuffer::FindTagWord(ExState &State) { + char word[MAXSEARCH + 1]; + PELine L = VLine(CP.Row); + int P, len = 0; + + P = CharOffset(L, CP.Col); + while ((P > 0) && ((ChClass(L->Chars[P - 1]) == 1) || (L->Chars[P - 1] == '_'))) + P--; + while (len < int(sizeof(word)) && P < L->Count && (ChClass(L->Chars[P]) == 1 || L->Chars[P] == '_')) + word[len++] = L->Chars[P++]; + word[len] = 0; + if (len == 0) { + Msg(S_INFO, "No word at cursor."); + return 0; + } + + int j = 2; + while (j--) { + int i; + + i = TagFind(this, View, word); + if (i > 0) + return 1; + else if (j && (i < 0)) { + /* Try autoload tags */ + if (View->ExecCommand(ExTagLoad, State) == 0) + break; + } else { + Msg(S_INFO, "Tag '%s' not found.", word); + break; + } + } + return 0; +} diff --git a/src/e_tags.cpp b/src/e_tags.cpp new file mode 100644 index 0000000..ad75353 --- /dev/null +++ b/src/e_tags.cpp @@ -0,0 +1,589 @@ +/* e_tags.cpp * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#include "fte.h" + +#ifdef CONFIG_TAGS +struct TagData { + int Tag; // tag name pos + int FileName; + int TagBase; // name of tag file + int Line; + int StrFind; // string to find +}; + +struct TagStack { + char *FileName; + int Line, Col; + TagStack *Next; + int TagPos; + char *CurrentTag; +}; + +static char *TagMem = 0; +static int TagLen = 0; +static int ATagMem = 0; + +static int CTags = 0; // number of tags +static int ATags = 0; +static TagData *TagD = 0; +static int *TagI = 0; +static int TagFileCount = 0; +static int *TagFiles = 0; + +static int TagFilesLoaded = 0; // tag files are loaded at first lookup +static char *CurrentTag = 0; +static int TagPosition = -1; +static TagStack *TStack; + +static int AllocMem(char *Mem, int Len) { /*FOLD00*/ + int N = 1024; + char *NM; + int TagPos = TagLen; + + while (N < TagLen + Len) N <<= 1; + if (ATagMem < N || TagMem == 0) { + NM = (char *)realloc((void *)TagMem, N); + if (NM == 0) + return -1; + TagMem = NM; + ATagMem = N; + } + memcpy(TagMem + TagLen, Mem, Len); + TagLen += Len; + return TagPos; +} + +static int AddTag(int Tag, int FileName, int TagBase, int Line, int StrFind) { /*FOLD00*/ + int N; + + N = 1024; + while (N < CTags + 1) N <<= 1; + if (ATags < N || TagD == 0) { + TagData *ND; + + ND = (TagData *)realloc((void *)TagD, N * sizeof(TagData)); + if (ND == 0) + return -1; + TagD = ND; + ATags = N; + } + TagD[CTags].Tag = Tag; + TagD[CTags].Line = Line; + TagD[CTags].FileName = FileName; + TagD[CTags].TagBase = TagBase; + TagD[CTags].StrFind = StrFind; + CTags++; + return 0; +} + +#if defined(__IBMCPP__) +int _LNK_CONV cmptags(const void *p1, const void *p2) { +#else +int cmptags(const void *p1, const void *p2) { +#endif + return strcmp(TagMem + TagD[*(int *)p1].Tag, + TagMem + TagD[*(int *)p2].Tag); +} + +int SortTags() { /*FOLD00*/ + int *NI; + int i; + + if (CTags == 0) + return 0; + + NI = (int *)realloc((void *)TagI, CTags * sizeof(int)); + if (NI == 0) + return -1; + TagI = NI; + for (i = 0; i < CTags; i++) + TagI[i] = i; + + qsort(TagI, CTags, sizeof(TagI[0]), cmptags); + + return 0; +} + +int TagsLoad(int id) { /*FOLD00*/ + //char line[2048]; + char *tags; + int fd; + struct stat sb; + long size; + + free(TagI); + TagI = 0; + + if ((fd = open(TagMem + TagFiles[id], O_BINARY | O_RDONLY)) == -1) + return -1; + + if (fstat(fd, &sb) == -1) + return -1; + + if ((tags = (char *)malloc(sb.st_size)) == 0) { + close(fd); + return -1; + } + + size = read(fd, tags, sb.st_size); + close(fd); + if (size != sb.st_size) + return -1; + + if (TagMem == 0) { // preallocate (useful when big file) + char *NM; + + NM = (char *)realloc((void *)TagMem, TagLen + sb.st_size); + if (NM != 0) { + TagMem = NM; + ATagMem = TagLen + sb.st_size; + } + } + + char *p = tags; + char *e = tags + sb.st_size; + + char *LTag, *LFile, *LLine; + int TagL, FileL/*, LineL*/; + int MTag, MFile; + + while (p < e) { + LTag = p; + while (p < e && *p != '\t') p++; + if (p < e && *p == '\t') *p++ = 0; + else break; + TagL = p - LTag; + LFile = p; + while (p < e && *p != '\t') p++; + if (p < e && *p == '\t') *p++ = 0; + else break; + FileL = p - LFile; + LLine = p; + while (p < e && *p != '\r' && *p != '\n') p++; + if (p < e && *p == '\r') *p++ = 0; // optional + if (p < e && *p == '\n') *p++ = 0; + else break; + //LineL = p - LLine; + + MTag = AllocMem(LTag, TagL + FileL); + + if (MTag == -1) + break; + + MFile = MTag + TagL; + + if (LLine[0] == '/') { + char *AStr = LLine; + char *p = AStr + 1; + char *d = AStr; + int MStr; + + while (*p) { + if (*p == '\\') { + p++; + if (*p) + *d++ = *p++; + } else if (*p == '^' || *p == '$') p++; + else if (*p == '/') + break; + else + *d++ = *p++; + } + *d = 0; + if (stricmp(d - 10, "/*FOLD00*/") == 0) + d[-11] = 0; /* remove our internal folds */ + + MStr = AllocMem(AStr, strlen(AStr) + 1); + if (MStr == -1) + break; + + if (AddTag(MTag, MFile, TagFiles[id], -1, MStr) == -1) + break; + } else { + if (AddTag(MTag, MFile, TagFiles[id], atoi(LLine), -1) == -1) + break; + } + } + free(tags); + return 0; +} + +int TagsAdd(char *FileName) { /*FOLD00*/ + int *NewT; + int NewF; + + NewF = AllocMem(FileName, strlen(FileName) + 1); + if (NewF == -1) + return 0; + + NewT = (int *)realloc((void *)TagFiles, (TagFileCount + 1) * sizeof(int)); + if (NewT == 0) + return 0; + TagFiles = NewT; + TagFiles[TagFileCount++] = NewF; + return 1; +} + +int TagsSave(FILE *fp) { /*FOLD00*/ + for (int i = 0; i < TagFileCount; i++) + fprintf(fp, "T|%s\n", TagMem + TagFiles[i]); + return 1; +} + +static void ClearTagStack() { /*FOLD00*/ + TagStack *T; + + if (CurrentTag) { + free(CurrentTag); + CurrentTag = 0; + } + TagPosition = -1; + while (TStack) { + T = TStack; + TStack = TStack->Next; + + free(T->CurrentTag); + free(T->FileName); + free(T); + } +} + +int TagLoad(char *FileName) { /*FOLD00*/ + if (TagsAdd(FileName) == 0) + return 0; + ClearTagStack(); + if (TagFilesLoaded) { + if (TagsLoad(TagFileCount - 1) == -1) { + return 0; + } + if (SortTags() == -1) { + TagClear(); + return 0; + } + } + return 1; +} + +static int LoadTagFiles() { /*FOLD00*/ + int i; + + assert(TagFilesLoaded == 0); + for (i = 0; i < TagFileCount; i++) + if (TagsLoad(i) == -1) { + TagClear(); + return 0; + } + if (SortTags() == -1) { + TagClear(); + return 0; + } + TagFilesLoaded = 1; + return 1; +} + +void TagClear() { /*FOLD00*/ + free(TagD); + free(TagI); + TagD = 0; + TagI = 0; + CTags = 0; + ATags = 0; + + free(TagFiles); + TagFiles = 0; + TagFileCount = 0; + TagFilesLoaded = 0; + + free(TagMem); + TagMem = 0; + TagLen = 0; + ATagMem = 0; + + ClearTagStack(); +} + +static int GotoFilePos(EView *View, char *FileName, int Line, int Col) { /*FOLD00*/ + if (FileLoad(0, FileName, 0, View) == 0) + return 0; + if (((EBuffer *)ActiveModel)->Loaded == 0) + ((EBuffer *)ActiveModel)->Load(); + ((EBuffer *)ActiveModel)->CenterNearPosR(Col, Line); + return 1; +} + +static int GotoTag(int M, EView *View) { /*FOLD00*/ + char path[MAXPATH]; + char Dir[MAXPATH]; + TagData *TT = &TagD[TagI[M]]; + + JustDirectory(TagMem + TT->TagBase, Dir); + + if (IsFullPath(TagMem + TT->FileName)) { + strcpy(path, TagMem + TT->FileName); + } else { + strcpy(path, Dir); + Slash(path, 1); + strcat(path, TagMem + TT->FileName); + } + if (TT->Line != -1) { + if (GotoFilePos(View, path, TT->Line - 1, 0) == 0) + return 0; + } else { + if (GotoFilePos(View, path, 0, 0) == 0) + return 0; + if (((EBuffer *)ActiveModel)->FindStr(TagMem + TT->StrFind, strlen(TagMem + TT->StrFind), 0) == 0) + return 0; + } + ((EBuffer *)ActiveModel)->FindStr(TagMem + TT->Tag, strlen(TagMem + TT->Tag), 0); + return 1; +} + +static int PushPos(EBuffer *B) { /*FOLD00*/ + TagStack *T; + + T = (TagStack *)malloc(sizeof(TagStack)); + if (T == 0) + return 0; + T->FileName = strdup(B->FileName); + if (T->FileName == 0) { + free(T); + return 0; + } + T->Line = B->VToR(B->CP.Row); + T->Col = B->CP.Col; + T->Next = TStack; + T->CurrentTag = CurrentTag; + CurrentTag = 0; + T->TagPos = TagPosition; + TagPosition = -1; + TStack = T; + return 1; +} + +int TagGoto(EView *View, char *Tag) { + assert(Tag != 0); + + if (TagFilesLoaded == 0) + if (LoadTagFiles() == 0) + return 0; + + int L = 0, R = CTags, M, cmp; + + if (CTags == 0) + return 0; + + while (L < R) { + M = (L + R) / 2; + cmp = strcmp(Tag, TagMem + TagD[TagI[M]].Tag); + if (cmp == 0) { + while (M > 0 && strcmp(Tag, TagMem + TagD[TagI[M - 1]].Tag) == 0) + M--; + + if (GotoTag(M, View) == 0) + return 0; + + CurrentTag = strdup(Tag); + TagPosition = M; + return 1; + } else if (cmp < 0) { + R = M; + } else { + L = M + 1; + } + } + return 0; // tag not found +} + +int TagFind(EBuffer *B, EView *View, char *Tag) { /*FOLD00*/ + assert(View != 0 && Tag != 0 && B != 0); + + if (TagFilesLoaded == 0) + if (LoadTagFiles() == 0) + return 0; + + int L = 0, R = CTags, M, cmp; + + if (CurrentTag) { + if (strcmp(CurrentTag, Tag) == 0) { + if (PushPos(B) == 0) + return 0; + + CurrentTag = strdup(Tag); + if (CurrentTag == 0) + return 0; + TagPosition = TStack->TagPos; + + return TagNext(View); + } + } + + if (CTags == 0) + return -1; + + while (L < R) { + M = (L + R) / 2; + cmp = strcmp(Tag, TagMem + TagD[TagI[M]].Tag); + if (cmp == 0) { + while (M > 0 && strcmp(Tag, TagMem + TagD[TagI[M - 1]].Tag) == 0) + M--; + + if (PushPos(B) == 0) + return 0; + + if (GotoTag(M, View) == 0) + return 0; + + CurrentTag = strdup(Tag); + TagPosition = M; + + return 1; + } else if (cmp < 0) { + R = M; + } else { + L = M + 1; + } + } + return 0; // tag not found +} + +int TagDefined(char *Tag) { + int L = 0, R = CTags, M, cmp; + + if (TagFilesLoaded == 0) // !!! always? + if (LoadTagFiles() == 0) + return 0; + + if (CTags == 0) + return 0; + + while (L < R) { + M = (L + R) / 2; + cmp = strcmp(Tag, TagMem + TagD[TagI[M]].Tag); + if (cmp == 0) + return 1; + else if (cmp < 0) + R = M; + else + L = M + 1; + } + return 0; // tag not found +} + +int TagComplete(char **Words, int *WordsPos, int WordsMax, char *Tag) { + if ((Tag == NULL) || (Words == NULL) || (*WordsPos >= WordsMax)) + return 0; + + if (TagFilesLoaded == 0) + if (LoadTagFiles() == 0) + return 0; + + if (CTags == 0) + return 0; + + int L = 0, R = CTags, len = strlen(Tag); + + while (L < R) { + int c, M; + + M = (L + R) / 2; + c = strncmp(Tag, TagMem + TagD[TagI[M]].Tag, len); + if (c == 0) { + while (M > 0 && + strncmp(Tag, TagMem + TagD[TagI[M - 1]].Tag, len) == 0) + M--; // find begining + int N = M, w = 0; + while(strncmp(Tag, TagMem + TagD[TagI[N]].Tag, len) == 0) { + // the first word is not tested for previous match + if (!w || strcmp(TagMem + TagD[TagI[N]].Tag, + TagMem + TagD[TagI[N-1]].Tag)) { + int l = strlen(TagMem + TagD[TagI[N]].Tag) - len; + if (l > 0) { + char *s = new char[l + 1]; + if (s != NULL) { + strcpy(s, TagMem + TagD[TagI[N]].Tag + len); + Words[(*WordsPos)++] = s; + w++; // also mark the first usage + if (*WordsPos >= WordsMax) + break; + } else + break; // how about using exceptions + } + } + N++; + } + return w; + } else if (c < 0) { + R = M; + } else { + L = M + 1; + } + } + return 0; // tag not found +} + +int TagNext(EView *View) { /*FOLD00*/ + assert(View != 0); + + if (CurrentTag == 0 || TagPosition == -1) { + return 0; + } + + if (TagPosition < CTags - 1 && strcmp(CurrentTag, TagMem + TagD[TagI[TagPosition + 1]].Tag) == 0) { + TagPosition++; + if (GotoTag(TagPosition, View) == 0) + return 0; + return 1; + } + View->Msg(S_INFO, "No next match for tag."); + return 0; +} + +int TagPrev(EView *View) { /*FOLD00*/ + assert(View != 0); + + if (CurrentTag == 0 || TagPosition == -1) { + View->Msg(S_INFO, "No current tag."); + return 0; + } + + if (TagPosition > 0 && strcmp(CurrentTag, TagMem + TagD[TagI[TagPosition - 1]].Tag) == 0) { + TagPosition--; + if (GotoTag(TagPosition, View) == 0) + return 0; + return 1; + } + View->Msg(S_INFO, "No previous match for tag."); + return 0; +} + +int TagPop(EView *View) { /*FOLD00*/ + TagStack *T = TStack; + + assert(View != 0); + + if (T) { + TStack = T->Next; + + if (CurrentTag) + free(CurrentTag); + CurrentTag = T->CurrentTag; + TagPosition = T->TagPos; + + if (GotoFilePos(View, T->FileName, T->Line, T->Col) == 0) { + free(T); + return 0; + } + free(T); + return 1; + } + View->Msg(S_INFO, "Tag stack empty."); + return 0; +} + +#endif diff --git a/src/e_tags.h b/src/e_tags.h new file mode 100644 index 0000000..5741fc9 --- /dev/null +++ b/src/e_tags.h @@ -0,0 +1,31 @@ +/* e_tags.h + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#ifndef __TAGS_H +#define __TAGS_H + +#ifdef CONFIG_TAGS + +int TagsAdd(char *FileName); +int TagsSave(FILE *fp); +int TagsLoad(int id); + +int TagLoad(char *FileName); +void TagClear(); +int TagGoto(EView *V, char *Tag); +int TagDefined(char *Tag); +int TagFind(EBuffer *B, EView *V, char *Tag); +int TagComplete(char **Words, int *WordsPos, int WordsMax, char *Tag); +int TagNext(EView *V); +int TagPrev(EView *V); +int TagPop(EView *V); + +#endif + +#endif diff --git a/src/e_trans.cpp b/src/e_trans.cpp new file mode 100644 index 0000000..299cf7a --- /dev/null +++ b/src/e_trans.cpp @@ -0,0 +1,269 @@ +/* e_trans.cpp + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#include "fte.h" +#include + +// FLAW: NULL characters can not be translated, need escaping +int ParseTrans(unsigned char *S, unsigned char *D, TransTable tab) { + unsigned char Dest[512]; + unsigned char A, B; + unsigned int i; + + if (S == 0 || D == 0) + return 0; + + strncpy((char *)Dest, (char *)D, sizeof(Dest) - 1); Dest[sizeof(Dest) - 1] = 0; + D = Dest; + + // no translation + for (i = 0; i < 256; i++) + tab[i] = (unsigned char)i; + + while (*S && *D) { + if (S[0] && S[1] == '-' && S[2]) { + if (S[0] <= S[2]) { + A = (*S)++; + if (S[0] >= S[2]) + S += 2; + } else { + A = (*S)--; + if (S[0] <= S[2]) + S += 2; + } + } else { + A = *S++; + } + if (D[0] && D[1] == '-' && D[2]) { + if (D[0] <= D[2]) { + B = (*D)++; + if (D[0] >= D[2]) + D += 2; + } else { + B = (*D)--; + if (D[0] <= D[2]) + D += 2; + } + } else { + B = *D++; + } + tab[A] = B; + } + if (*S != *D) // one was too short + return 0; + return 1; +} + +int MakeTrans(TransTable tab, int What) { + int i; + + // no translation + for (i = 0; i <= 255; i++) + tab[i] = (unsigned char)i; + + switch (What) { + case ccToggle: + case ccUp: + for (i = 33; i <= 255; i++) + if (isalpha(i) && (toupper(i) != i)) + tab[i] = (unsigned char) toupper(i); + if (What != ccToggle) + break; + case ccDown: + for (i = 33; i <= 255; i++) + if (isalpha(i) && (i == tab[i]) && (tolower(i) != i)) + tab[i] = (unsigned char) tolower(i); + break; + default: + return 0; + } + return 1; +} + +int EBuffer::BlockTrans(TransTable tab) { + int L, I, B, E; + PELine LL; + + if (CheckBlock() == 0) return 0; + if (RCount == 0) return 0; + + for (L = BB.Row; L <= BE.Row; L++) { + LL = RLine(L); + B = 0; + E = 0; + switch (BlockMode) { + case bmLine: + if (L == BE.Row) + E = 0; + else + E = LL->Count; + break; + case bmColumn: + if (L == BE.Row) + E = 0; + else { + B = CharOffset(LL, BB.Col); + E = CharOffset(LL, BE.Col); + } + break; + case bmStream: + if (L == BB.Row && L == BE.Row) { + B = CharOffset(LL, BB.Col); + E = CharOffset(LL, BE.Col); + } else if (L == BB.Row) { + B = CharOffset(LL, BB.Col); + E = LL->Count; + } else if (L == BE.Row) { + B = 0; + E = CharOffset(LL, BE.Col); + } else { + B = 0; + E = LL->Count; + } + break; + } + if (B > LL->Count) + B = LL->Count; + if (E > LL->Count) + E = LL->Count; + if (E > B) { + if (ChgChars(L, B, E - B, 0) == 0) return 0; + for (I = B; I < E; I++) + LL->Chars[I] = tab[(unsigned char)LL->Chars[I]]; + } + } + Draw(BB.Row, BE.Row); + return 1; +} + +int EBuffer::CharTrans(TransTable tab) { + PELine L = VLine(CP.Row); + unsigned int P = CharOffset(L, CP.Col); + + if (P >= (unsigned int)L->Count) return 0; + if (ChgChars(CP.Row, P, 1, 0) == 0) return 0; + L->Chars[P] = tab[(unsigned char)L->Chars[P]]; + return 1; +} + +int EBuffer::LineTrans(TransTable tab) { + PELine L = VLine(CP.Row); + int I; + + if (L->Count > 0) { + if (ChgChars(CP.Row, 0, L->Count, 0) == 0) return 0; + for (I = 0; I < L->Count; I++) + L->Chars[I] = tab[(unsigned char)L->Chars[I]]; + } + return 1; +} + +int EBuffer::CharCaseUp() { + TransTable tab; + + MakeTrans(tab, ccUp); + return CharTrans(tab); +} + +int EBuffer::CharCaseDown() { + TransTable tab; + + MakeTrans(tab, ccDown); + return CharTrans(tab); +} + +int EBuffer::CharCaseToggle() { + TransTable tab; + + MakeTrans(tab, ccToggle); + return CharTrans(tab); +} + +int EBuffer::LineCaseUp() { + TransTable tab; + + MakeTrans(tab, ccUp); + return LineTrans(tab); +} + +int EBuffer::LineCaseDown() { + TransTable tab; + + MakeTrans(tab, ccDown); + return LineTrans(tab); +} + +int EBuffer::LineCaseToggle() { + TransTable tab; + + MakeTrans(tab, ccToggle); + return LineTrans(tab); +} + +int EBuffer::BlockCaseUp() { + TransTable tab; + + MakeTrans(tab, ccUp); + return BlockTrans(tab); +} + +int EBuffer::BlockCaseDown() { + TransTable tab; + + MakeTrans(tab, ccDown); + return BlockTrans(tab); +} + +int EBuffer::BlockCaseToggle() { + TransTable tab; + + MakeTrans(tab, ccToggle); + return BlockTrans(tab); +} + +int EBuffer::GetTrans(ExState &State, TransTable tab) { + unsigned char TrS[512] = ""; + unsigned char TrD[512] = ""; + + if (State.GetStrParam(View, (char *)TrS, sizeof(TrS)) == 0) + if (View->MView->Win->GetStr("Trans From", sizeof(TrS), (char *)TrS, HIST_TRANS) == 0) + return 0; + if (State.GetStrParam(View, (char *)TrD, sizeof(TrD)) == 0) + if (View->MView->Win->GetStr("Trans To", sizeof(TrS), (char *)TrD, HIST_TRANS) == 0) + return 0; + if (ParseTrans(TrS, TrD, tab) == 0) { + Msg(S_ERROR, "Bad Trans Arguments %s %s.", TrS, TrD); + return 0; + } + return 1; +} + +int EBuffer::CharTrans(ExState &State) { + TransTable tab; + + if (GetTrans(State, tab) == 0) + return 0; + return CharTrans(tab); +} + +int EBuffer::LineTrans(ExState &State) { + TransTable tab; + + if (GetTrans(State, tab) == 0) + return 0; + return LineTrans(tab); +} + +int EBuffer::BlockTrans(ExState &State) { + TransTable tab; + + if (GetTrans(State, tab) == 0) + return 0; + return BlockTrans(tab); +} diff --git a/src/e_undo.cpp b/src/e_undo.cpp new file mode 100644 index 0000000..19e4623 --- /dev/null +++ b/src/e_undo.cpp @@ -0,0 +1,370 @@ +/* e_undo.cpp + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#include "fte.h" + +int EBuffer::NextCommand() { + if (Match.Row != -1) { + Draw(Match.Row, Match.Row); + Match.Col = Match.Row = -1; + } + if (View) + View->SetMsg(0); +#ifdef CONFIG_UNDOREDO + return BeginUndo(); +#else + return 1; +#endif +} + +#ifdef CONFIG_UNDOREDO + +int EBuffer::PushBlockData() { + if (BFI(this, BFI_Undo) == 0) return 1; + if (PushULong(BB.Col) == 0) return 0; + if (PushULong(BB.Row) == 0) return 0; + if (PushULong(BE.Col) == 0) return 0; + if (PushULong(BE.Row) == 0) return 0; + if (PushULong(BlockMode) == 0) return 0; + if (PushUChar(ucBlock) == 0) return 0; + return 1; +} + +int EBuffer::BeginUndo() { + US.NextCmd = 1; + return 1; +} + +int EBuffer::EndUndo() { + int N = US.Num - 1; + + assert(N >= 0); + if (N >= 1) { + int Order = 1; + + while (Order < N) Order <<= 1; + + US.Data = (void **) realloc(US.Data, sizeof(void *) * Order); + US.Top = (int *) realloc(US.Top, sizeof(int) * Order); + US.Num--; + } else { + free(US.Data); US.Data = 0; + free(US.Top); US.Top = 0; + US.Num = 0; + } + return 1; +} + +int EBuffer::PushULong(unsigned long l) { +// static unsigned long x = l; + return PushUData(&l, sizeof(unsigned long)); +} + +int EBuffer::PushUChar(unsigned char ch) { + return PushUData(&ch, sizeof(unsigned char)); +} + + +int EBuffer::PushUData(void *data, int len) { + int N; + int Order = 1; + +// printf("UPUSH: %d %c\n", len, *(char *)data); fflush(stdout); + + if (BFI(this, BFI_Undo) == 0) return 0; + if (US.Record == 0) return 1; + if (US.NextCmd || US.Num == 0 || US.Data == 0 || US.Top == 0) { + N = US.Num; + if ((BFI(this, BFI_UndoLimit) == -1) || (US.Undo) || (US.Num < BFI(this, BFI_UndoLimit))) { + N++; + US.Data = (void **) realloc(US.Data, sizeof(void *) * (N | 255)); + US.Top = (int *) realloc(US.Top, sizeof(int) * (N | 255)); + if (US.Num == US.UndoPtr && !US.Undo) + US.UndoPtr++; + US.Num++; + } else { + N = US.Num; + free(US.Data[0]); + memmove(US.Data, US.Data + 1, (N - 1) * sizeof(US.Data[0])); + memmove(US.Top, US.Top + 1, (N - 1) * sizeof(US.Top[0])); + } + assert(US.Data); + assert(US.Top); + N = US.Num - 1; + US.Data[N] = 0; + US.Top[N] = 0; + if (US.NextCmd == 1) { + US.NextCmd = 0; +// puts("\x7"); + if (PushULong(CP.Col) == 0) return 0; + if (PushULong(CP.Row) == 0) return 0; + if (PushUChar(ucPosition) == 0) return 0; +// puts("\x7"); + } + US.NextCmd = 0; + } + + N = US.Num - 1; + assert(N >= 0); + + if (US.Undo == 0) US.UndoPtr = US.Num; + + while (Order < (US.Top[N] + len)) Order <<= 1; + US.Data[N] = realloc(US.Data[N], Order); + memcpy((char *) US.Data[N] + US.Top[N], data, len); + US.Top[N] += len; + return 1; +} + +int EBuffer::GetUData(int No, int pos, void **data, int len) { + int N; + + if (No == -1) + N = US.Num - 1; + else + N = No; + + if (BFI(this, BFI_Undo) == 0) return 0; + if (N < 0) return 0; + if (US.Data[N] == 0) return 0; + if (US.Top[N] == 0) return 0; + + if (pos == -1) + pos = US.Top[N]; + + + if (pos == 0) + return 0; +// printf("N,pos = %d,%d len = %d\n", N, pos, len); + + assert(pos >= len); + *data = ((char *) US.Data[N]) + pos - len; + return 1; +} + +#define UGETC(rc,no,pos,what) \ + do { void *d; \ + rc = GetUData(no, pos, &d, sizeof(unsigned char)); \ + *(unsigned char *)&what = *(unsigned char *)d; \ + pos -= sizeof(unsigned char); \ + } while (0) + +#define UGET(rc,no,pos,what) \ + do { void *d; \ + rc = GetUData(no, pos, &d, sizeof(what)); \ + memcpy((void *)&what, d, sizeof(what)); \ + pos -= sizeof(what); \ + } while (0) + +int EBuffer::Undo(int undo) { + unsigned char UndoCmd; + int rc; + unsigned long Line; + unsigned long Len; + unsigned long ACount; + unsigned long Col; + void *data; + + int No; + int Pos; + + if (BFI(this, BFI_Undo) == 0) + return 0; + + if (undo) + No = US.UndoPtr - 1; + else + No = US.Num - 1; + + Pos = US.Top[No]; + + if (No == 0 && Pos == 0) { + //puts("bottom"); + return 0; + } +// for (int i = 0; i < Pos; i++) { +// printf("%d: %d\n", i, ((char *)US.Data[No])[i]); +// } + +// printf("Undo %d %d,%d\n", undo, No, Pos); fflush(stdout); + +// fprintf(stderr, "\nNo = %d, Num = %d\n", No, US.Num); + UGETC(rc, No, Pos, UndoCmd); + while (rc == 1) { +// printf("%d Undo %d %d,%d\n", UndoCmd, undo, No, Pos); fflush(stdout); + // for (int i = 0; i < Pos; i++) { +// printf("%d: %d\n", i, ((char *)US.Data[No])[i]); +// } + switch (UndoCmd) { + case ucInsLine: + UGET(rc, No, Pos, Line); if (rc == 0) return 0; +// printf("\tDelLine %d\n", Line); + if (DelLine(Line) == 0) return 0; + break; + + case ucDelLine: + UGET(rc, No, Pos, Line); if (rc == 0) return 0; + UGET(rc, No, Pos, Len); if (rc == 0) return 0; + if (GetUData(No, Pos, &data, Len) == 0) return 0; +// printf("\tInsLine %d\n", Line); + if (InsLine(Line, 0) == 0) return 0; +// printf("\tInsText %d - %d\n", Line, Len); + if (InsText(Line, 0, Len, (char *) data) == 0) return 0; + Pos -= Len; + break; + + case ucInsChars: + UGET(rc, No, Pos, ACount); if (rc == 0) return 0; + UGET(rc, No, Pos, Col); if (rc == 0) return 0; + UGET(rc, No, Pos, Line); if (rc == 0) return 0; +// printf("\tDelChars %d %d %d\n", Line, Col, ACount); + if (DelChars(Line, Col, ACount) == 0) return 0; + break; + + case ucDelChars: + UGET(rc, No, Pos, Line); if (rc == 0) return 0; + UGET(rc, No, Pos, Col); if (rc == 0) return 0; + UGET(rc, No, Pos, ACount); if (rc == 0) return 0; + if (GetUData(No, Pos, &data, ACount) == 0) return 0; +// printf("\tInsChars %d %d %d\n", Line, Col, ACount); + if (InsChars(Line, Col, ACount, (char *) data) == 0) return 0; + Pos -= ACount; + break; + + case ucPosition: + UGET(rc, No, Pos, Line); if (rc == 0) return 0; + UGET(rc, No, Pos, Col); if (rc == 0) return 0; +// printf("\tSetPos %d %d\n", Line, Col); + if (SetPos(Col, Line) == 0) return 0; + break; + + case ucBlock: + { + EPoint P; + unsigned long l; + +// printf("\tBlock\n"); + UGET(rc, No, Pos, l); if (rc == 0) return 0; + if (BlockMode != (int)l) BlockRedraw(); + BlockMode = l; + UGET(rc, No, Pos, l); if (rc == 0) return 0; P.Row = l; + UGET(rc, No, Pos, l); if (rc == 0) return 0; P.Col = l; + if (SetBE(P) == 0) return 0; + UGET(rc, No, Pos, l); if (rc == 0) return 0; P.Row = l; + UGET(rc, No, Pos, l); if (rc == 0) return 0; P.Col = l; + if (SetBB(P) == 0) return 0; + } + break; + + case ucFoldCreate: + // puts("ucFoldCreate"); + UGET(rc, No, Pos, Line); if (rc == 0) return 0; + if (FoldDestroy(Line) == 0) return 0; + break; + + case ucFoldDestroy: + // puts("ucFoldDestroy"); + { + unsigned long level; + int ff; + + UGET(rc, No, Pos, Line); if (rc == 0) return 0; + UGET(rc, No, Pos, level); if (rc == 0) return 0; + if (FoldCreate(Line) == 0) return 0; + + ff = FindFold(Line); + assert(ff != -1); + FF[ff].level = (unsigned char) level; + } + break; + case ucFoldPromote: + // puts("ucFoldPromote"); + UGET(rc, No, Pos, Line); if (rc == 0) return 0; + if (FoldDemote(Line) == 0) return 0; + break; + + case ucFoldDemote: + // puts("ucFoldDemote"); + UGET(rc, No, Pos, Line); if (rc == 0) return 0; + if (FoldPromote(Line) == 0) return 0; + break; + + case ucFoldOpen: + // puts("ucFoldOpen"); + UGET(rc, No, Pos, Line); if (rc == 0) return 0; + if (FoldClose(Line) == 0) return 0; + break; + + case ucFoldClose: + // puts("ucFoldClose"); + UGET(rc, No, Pos, Line); if (rc == 0) return 0; + if (FoldOpen(Line) == 0) return 0; + break; + + case ucModified: +// printf("\tModified\n"); + Modified = 0; + break; + + default: + assert(1 == "Oops: invalid undo command.\n"[0]); + } +// puts("\tok"); + +// fprintf(stderr, "\nNo = %d, Num = %d\n", No, US.Num); + UGETC(rc, No, Pos, UndoCmd); + } + + if (undo) + US.UndoPtr--; + else { + US.UndoPtr++; + free(US.Data[No]); + if (EndUndo() == 0) return 0; + } + + return 1; +} + +int EBuffer::Redo() { + int rc; + + if (BFI(this, BFI_Undo) == 0) return 0; + +// US.NextCmd = 0; // disable auto push position + + if (US.Num == 0 || US.UndoPtr == US.Num) { + Msg(S_INFO, "Nothing to redo."); + return 0; + } + + US.Record = 0; + rc = Undo(0); + US.Record = 1; + return rc; +} + +int EBuffer::Undo() { + int rc; + + if (BFI(this, BFI_Undo) == 0) return 0; + + assert(US.Num >= 0); + assert(US.UndoPtr >= 0); + if (US.Num == 0 || US.UndoPtr == 0) { + Msg(S_INFO, "Nothing to undo."); + return 0; + } + + US.Undo = 1; + rc = Undo(1); + US.Undo = 0; + return rc; +} +#endif diff --git a/src/e_undo.h b/src/e_undo.h new file mode 100644 index 0000000..fb2e56c --- /dev/null +++ b/src/e_undo.h @@ -0,0 +1,43 @@ +/* e_undo.h + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#ifndef __UNDO_H__ +#define __UNDO_H__ + +/* + * only core operations can be directly undone + * - Insert # of Lines + * - Delete # of Lines + * - Insert # Line + * - Delete Line Text + * - Insert Line Text + * - Positioning + * - Block marking + */ + +#define ucInsLine 1 +#define ucDelLine 2 +#define ucInsChars 3 +#define ucDelChars 4 + +#define ucJoinLine 5 +#define ucSplitLine 6 + +#define ucPosition 7 +#define ucBlock 8 +#define ucModified 9 + +#define ucFoldCreate 11 +#define ucFoldDestroy 12 +#define ucFoldPromote 13 +#define ucFoldDemote 14 +#define ucFoldOpen 15 +#define ucFoldClose 16 + +#endif diff --git a/src/e_unix.cpp b/src/e_unix.cpp new file mode 100644 index 0000000..01fc79c --- /dev/null +++ b/src/e_unix.cpp @@ -0,0 +1,87 @@ +/* e_unix.cpp + * + * Copyright (c) 1997, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#ifdef WINNT +#include "e_win32.cpp" +#else + +// UNIX specific routines + +#include "fte.h" + +#include +#include + +int EView::SysShowHelp(ExState &State, const char *word) { + char options[128] = ""; + char command[1024]; + char file[MAXPATH]; + + if (State.GetStrParam(this, options, sizeof(options) - 1) == 0) + options[0] = 0; + + char wordAsk[64] = ""; + if (word == 0) { + if (State.GetStrParam(this, wordAsk, sizeof(wordAsk) - 1) == 0) + if (MView->Win->GetStr("Keyword", + sizeof(wordAsk) - 1, wordAsk, HIST_DEFAULT) == 0) + return 0; + word = wordAsk; + } + + sprintf(file, "/tmp/fte%d-man-%s", getpid(), word); + sprintf(command, "%s %s %s >'%s' 2>&1", HelpCommand, options, word, file); + + /// !!! why is this needed ??? +#define SYSCALL(call) while(((call) == -1) && (errno == EINTR)) + pid_t pid; + int err, status; + + Msg(S_INFO, "Retrieving man page for %s, please wait", word); + + if ((pid = fork()) == 0) { + close(1); + SYSCALL(err = open(file, O_CREAT | O_WRONLY | O_APPEND, S_IRWXU)); + if (err != -1) { + close(2); + //dup(1); // ignore error output + close(0); + assert(open("/dev/null", O_RDONLY) == 0); + execlp("man", "man", +#ifndef AIX // current AIX's don't like the -a. + "-a", +#endif + word, NULL); + // execlp("/bin/sh", "sh", "-c", command, NULL); + } + perror("Can't Exec Command\n"); + exit(-1); + } else if (pid < 0) { + perror("Can't fork"); + return 0; + } + SYSCALL(err = waitpid(pid, &status, 0)); + if (err == -1) { + perror("Waitpid failed\n"); + return 0; + } + + // int rc = system(command); + + err = FileLoad(0, file, "CATBS", this); + unlink(file); + + if (err == 0){ + Msg(S_ERROR, "Error code %d retrieving manpage for %s", err, word); + return 0; + } + return 1; +} + +#endif diff --git a/src/e_win32.cpp b/src/e_win32.cpp new file mode 100644 index 0000000..55b5285 --- /dev/null +++ b/src/e_win32.cpp @@ -0,0 +1,39 @@ +/* e_win32.cpp + * + * Copyright (c) 1997, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +// Win32 (NT) specific routines + +#include "fte.h" + +#include + +int EView::SysShowHelp(ExState &State, const char *word) { + char file[MAXPATH] = ""; + + if (State.GetStrParam(this, file, sizeof(file) - 1) == 0) + if (MView->Win->GetStr("Help file", + sizeof(file) - 1, file, HIST_DEFAULT) == 0) + return 0; + + char wordAsk[64] = ""; + if (word == 0) { + if (State.GetStrParam(this, wordAsk, sizeof(wordAsk) - 1) == 0) + if (MView->Win->GetStr("Keyword", + sizeof(wordAsk) - 1, wordAsk, HIST_DEFAULT) == 0) + return 0; + word = wordAsk; + } + + //** Start WinHelp, + if (!WinHelp(0, file, HELP_KEY, (DWORD)word)) { + Msg(S_ERROR, "Failed to start WinHelp!"); + return 0; + } + return 1; +} diff --git a/src/egui.cpp b/src/egui.cpp new file mode 100644 index 0000000..81128b9 --- /dev/null +++ b/src/egui.cpp @@ -0,0 +1,1068 @@ +/* egui.cpp + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#include "fte.h" + +int LastEventChar = -1; + +EFrame::EFrame(int XSize, int YSize): GFrame(XSize, YSize) { + CMap = 0; + CModel = 0; + frames = this; +} + +EFrame::~EFrame() { +} + +void EFrame::Update() { + GxView *V = (GxView *)Active; + + if (V) { + if (CModel != ActiveModel && ActiveModel) { + char Title[256] = ""; //fte: "; + char STitle[256] = ""; //"fte: "; + + ActiveModel->GetTitle((char *)(Title + 0), sizeof(Title) - 0, + (char *)(STitle + 0), sizeof(STitle) - 0); + ConSetTitle(Title, STitle); + CModel = ActiveModel; + } + } + GFrame::Update(); +} + +void EFrame::UpdateMenu() { + GxView *V = (GxView *)Active; + EEventMap *Map = 0; + + if (V) + Map = V->GetEventMap(); + + if (Map != CMap || CMap == 0) { + const char *Menu = 0; + const char *OMenu = 0; + // set menu + + if (CMap) + OMenu = CMap->GetMenu(EM_MainMenu); + if (Map) + Menu = Map->GetMenu(EM_MainMenu); + if (Menu == 0) + Menu = "Main"; + CMap = Map; + + if (OMenu && strcmp(OMenu, Menu) == 0) { + // ok + } else { + SetMenu(Menu); + } + } /*else if (CMap == 0 && Map == 0) { + SetMenu("Main"); + }*/ + + GFrame::UpdateMenu(); +} + +EGUI::EGUI(int &argc, char **argv, int XSize, int YSize): GUI(argc, argv, XSize, YSize) { + ActiveMap = 0; + OverrideMap = 0; + strcpy(CharMap, ""); +} + +EGUI::~EGUI() { +} + +int EGUI::ExecCommand(GxView *view, int Command, ExState &State) { + if (Command & CMD_EXT) + return ExecMacro(view, Command & ~CMD_EXT); + + if (Command == ExFail) + return ErFAIL; + + if (view->IsModelView()) { + ExModelView *V = (ExModelView *)view->Top; + EView *View = V->View; + + switch (Command) { + case ExFileClose: return FileClose(View, State); + case ExFileCloseAll: return FileCloseAll(View, State); + case ExExitEditor: return ExitEditor(View); + case ExIncrementalSearch: +#ifdef CONFIG_I_SEARCH + return View->MView->Win->IncrementalSearch(View); +#else + return ErFAIL; +#endif + } + } + switch (Command) { + case ExWinRefresh: view->Repaint(); return 1; + case ExWinNext: return WinNext(view); + case ExWinPrev: return WinPrev(view); + case ExShowEntryScreen: return ShowEntryScreen(); + case ExRunProgram: return RunProgram(State, view); + case ExRunProgramAsync: return RunProgramAsync(State, view); + case ExMainMenu: return MainMenu(State, view); + case ExShowMenu: return ShowMenu(State, view); + case ExLocalMenu: return LocalMenu(view); + case ExFrameNew: return FrameNew(); + case ExFrameNext: return FrameNext(view); + case ExFramePrev: return FramePrev(view); + + case ExWinHSplit: return WinHSplit(view); + case ExWinClose: return WinClose(view); + case ExWinZoom: return WinZoom(view); + case ExWinResize: return WinResize(State, view); + case ExDesktopSaveAs: return DesktopSaveAs(State, view); + case ExDesktopSave: + if (DesktopFileName[0] != 0) + return SaveDesktop(DesktopFileName); + return 0; + case ExChangeKeys: + { + char kmaps[64] = ""; + EEventMap *m; + + if (State.GetStrParam(0, kmaps, sizeof(kmaps)) == 0) { + SetOverrideMap(0, 0); + return 0; + } + m = FindEventMap(kmaps); + if (m == 0) + return 0; + SetOverrideMap(m->KeyMap, m->Name); + return 1; + } + } + return view->ExecCommand(Command, State); +} + +int EGUI::BeginMacro(GxView *view) { + view->BeginMacro(); + return 1; +} + +int EGUI::ExecMacro(GxView *view, int Macro) { + int i, j; + ExMacro *m; + ExState State; + + if (Macro == -1) + return ErFAIL; + + if (BeginMacro(view) == -1) + return ErFAIL; + + State.Macro = Macro; + State.Pos = 0; + m = &Macros[State.Macro]; + for (; State.Pos < m->Count; State.Pos++) { + i = State.Pos; + if (m->cmds[i].type != CT_COMMAND || + m->cmds[i].u.num == ExNop) + continue; + + for (j = 0; j < m->cmds[i].repeat; j++) { + State.Pos = i + 1; + if (ExecCommand(view, m->cmds[i].u.num, State) == 0 && !m->cmds[i].ign) + { + return ErFAIL; + } + } + State.Pos = i; + } + return ErOK; +} + +void EGUI::SetMsg(char *Msg) { + static char CharMap[128] = ""; + + if (Msg == 0) { + strcpy(CharMap, ""); + } else { + strcat(CharMap, "["); + strcat(CharMap, Msg); + strcat(CharMap, "]"); + } + if (ActiveModel) + ActiveModel->Msg(S_INFO, CharMap); +} + +void EGUI::SetOverrideMap(EKeyMap *aMap, char *ModeName) { + OverrideMap = aMap; + if (aMap == 0) + SetMsg(0); + else + SetMsg(ModeName); +} + +void EGUI::SetMap(EKeyMap *aMap, KeySel *ks) { + char key[32] = ""; + + ActiveMap = aMap; + if (ActiveMap == 0) { + SetMsg(0); + } else { + if (ks != 0) { + GetKeyName(key, *ks); + SetMsg(key); + } + } +} + +void EGUI::DispatchKey(GxView *view, TEvent &Event) { + EEventMap *EventMap; + EKeyMap *map; + EKey *key = 0; + char Ch; + + if (Event.Key.Code & kfModifier) + return; + + LastEventChar = -1; + if (GetCharFromEvent(Event, &Ch)) + LastEventChar = Ch; + + if ((EventMap = view->GetEventMap()) == 0) + return; + + map = EventMap->KeyMap; + + if (ActiveMap || OverrideMap) { + map = ActiveMap; + if (OverrideMap) + map = OverrideMap; + while (map) { + if ((key = map->FindKey(Event.Key.Code)) != 0) { + if (key->fKeyMap) { + SetMap(key->fKeyMap, &key->fKey); + Event.What = evNone; + return ; + } else { + SetMap(0, &key->fKey); + ExecMacro(view, key->Cmd); + Event.What = evNone; + return ; + } + } + // printf("Going up\n"); + map = map->fParent; + } + if (!OverrideMap) { + SetMap(0, 0); + Event.What = evNone; + } + return ; + } + while (EventMap) { + if (map) { + if ((key = map->FindKey(Event.Key.Code)) != 0) { + if (key->fKeyMap) { + SetMap(key->fKeyMap, &key->fKey); + Event.What = evNone; + return ; + } else { + ExecMacro(view, key->Cmd); + Event.What = evNone; + return ; + } + } + } + EventMap = EventMap->Parent; + if (EventMap == 0) break; + map = EventMap->KeyMap; + } +// if (GetCharFromEvent(Event, &Ch)) +// CharEvent(view, Event, Ch); + SetMap(0, 0); +} + +void EGUI::DispatchCommand(GxView *view, TEvent &Event) { + if (Event.Msg.Command > 65536 + 16384) + { // hack for PM toolbar + Event.Msg.Command -= 65536 + 16384; + BeginMacro(view); + ExState State; + State.Macro = 0; + State.Pos = 0; + ExecCommand(view, Event.Msg.Command, State); + Event.What = evNone; + } else if (Event.Msg.Command >= 65536) { + Event.Msg.Command -= 65536; + ExecMacro(view, Event.Msg.Command); + Event.What = evNone; + } +} + +void EGUI::DispatchEvent(GFrame *frame, GView *view, TEvent &Event) { + GxView *xview = (GxView *) view; + + if (Event.What == evNone || + (Event.What == evMouseMove && Event.Mouse.Buttons == 0)) + return ; + + if (Event.What == evNotify && Event.Msg.Command == cmPipeRead) { + Event.Msg.Model->NotifyPipe(Event.Msg.Param1); + return; + } + if (xview->GetEventMap() != 0) { + switch (Event.What) { + case evKeyDown: + DispatchKey(xview, Event); + break; + case evCommand: + if (Event.Msg.Command >= 65536) { + DispatchCommand(xview, Event); + } else { + switch (Event.Msg.Command) { + case cmClose: + { + assert(ActiveView != 0); + FrameClose(ActiveView->MView->Win); + return; + } + } + } + } + } + GUI::DispatchEvent(frame, view, Event); +#if defined(OS2) && !defined(DBMALLOC) && defined(CHECKHEAP) + if (_heapchk() != _HEAPOK) + DieError(0, "Heap memory is corrupt."); +#endif +} + +///////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////// + +int EGUI::WinNext(GxView *view) { + view->Parent->SelectNext(0); + return 1; +} + +int EGUI::WinPrev(GxView *view) { + view->Parent->SelectNext(1); + return 1; +} + +int EGUI::FileCloseX(EView *View, int CreateNew, int XClose) { + char Path[MAXPATH]; + + // this should never fail! + if (GetDefaultDirectory(View->Model, Path, sizeof(Path)) == 0) + return 0; + + if (View->Model->ConfQuit(View->MView->Win)) { + + View->Model->DeleteRelated(); + + // close everything that can be closed without confirmation if closing all + if (XClose) + while (View->Model->Next != View->Model && + View->Model->Next->CanQuit()) + delete View->Model->Next; + + View->DeleteModel(View->Model); + +#ifdef CONFIG_OBJ_DIRECTORY + if (ActiveModel == 0 && CreateNew) { + EView *V = ActiveView; + EModel *m = new EDirectory(0, &ActiveModel, Path); + assert(m != 0); + + do { + V = V->Next; + V->SelectModel(ActiveModel); + } while (V != ActiveView); + return 0; + } +#endif + + if (ActiveModel == 0) { + StopLoop(); + } + return 1; + } + return 0; +} + + +int EGUI::FileClose(EView *View, ExState &State) { + int x = 0; + + if (State.GetIntParam(View, &x) == 0) + x = OpenAfterClose; + + return FileCloseX(View, x); +} + +int EGUI::FileCloseAll(EView *View, ExState &State) { + int x = 0; + + if (State.GetIntParam(View, &x) == 0) + x = OpenAfterClose; + + while (ActiveModel) + if (FileCloseX(View, x, 1) == 0) return 0; + return 1; +} + +int EGUI::WinHSplit(GxView *View) { + GxView *view; + ExModelView *edit; + EView *win; + int W, H; + + View->ConQuerySize(&W, &H); + + if (H < 8) + return 0; + view = new GxView(View->Parent); + if (view == 0) + return 0; + win = new EView(ActiveModel); + if (win == 0) + return 0; + edit = new ExModelView(win); + if (edit == 0) + return 0; + view->PushView(edit); + view->Parent->SelectNext(0); + return 1; +} + +int EGUI::WinClose(GxView *V) { + EView *View = ActiveView; + + if (View->Next == View) { + // when closing last window, close all files + if (ExitEditor(View) == 0) + return 0; + } else { + View->MView->Win->Parent->SelectNext(0); + delete View->MView->Win; + } + return 1; +} + +int EGUI::WinZoom(GxView *View) { + GView *V = View->Next; + GView *V1; + + while (V) { + V1 = V; + if (V == View) + break; + V = V->Next; + delete V1; + } + return 1; +} + +int EGUI::WinResize(ExState &State, GxView *View) { + int Delta = 1; + + if (State.GetIntParam(0, &Delta)) { + if (View->ExpandHeight(Delta) == 0) + return 1; + } + return 0; +} + +int EGUI::ExitEditor(EView *View) { + EModel *B = ActiveModel; + + // check/save modified files + while (ActiveModel) { + if (ActiveModel->CanQuit()) ; + else { + View->SelectModel(ActiveModel); + int rc = ActiveModel->ConfQuit(View->MView->Win, 1); + if (rc == -2) { + View->FileSaveAll(); + break; + } + if (rc == 0) + return 0; + } + + ActiveModel = ActiveModel->Next; + if (ActiveModel == B) + break; + } + +#ifdef CONFIG_DESKTOP + if (SaveDesktopOnExit && DesktopFileName[0] != 0) + SaveDesktop(DesktopFileName); + else if (LoadDesktopMode == 2) { // Ask about saving? + GxView* gx = View->MView->Win; + + if (gx->GetStr("Save desktop As", + sizeof(DesktopFileName), DesktopFileName, + HIST_DEFAULT) != 0) + { + SaveDesktop(DesktopFileName); + } + } +#endif + + while (ActiveModel) { + View->Model->DeleteRelated(); // delete related views first + + while (View->Model->Next != View->Model && + View->Model->Next->CanQuit()) + delete View->Model->Next; + + View->DeleteModel(View->Model); + } + + StopLoop(); + return 1; +} + +int EGUI::ShowEntryScreen() { + return gui->ShowEntryScreen(); +} + +int EGUI::RunProgram(ExState &State, GxView *view) { + static char Cmd[512] = ""; + + if (ActiveModel) + SetDefaultDirectory(ActiveModel); + + if (State.GetStrParam(ActiveView, Cmd, sizeof(Cmd)) == 0) + if (view->GetStr("Run", sizeof(Cmd), Cmd, HIST_COMPILE) == 0) return 0; + gui->RunProgram(RUN_WAIT, Cmd); + return 1; +} + +int EGUI::RunProgramAsync(ExState &State, GxView *view) { + static char Cmd[512] = ""; + + if (ActiveModel) + SetDefaultDirectory(ActiveModel); + + if (State.GetStrParam(ActiveView, Cmd, sizeof(Cmd)) == 0) + if (view->GetStr("Run", sizeof(Cmd), Cmd, HIST_COMPILE) == 0) return 0; + gui->RunProgram(RUN_ASYNC, Cmd); + return 1; +} + +int EGUI::MainMenu(ExState &State, GxView *View) { + char s[3]; + + if (State.GetStrParam(0, s, sizeof(s)) == 0) + s[0] = 0; + + View->Parent->ExecMainMenu(s[0]); + return 1; +} + +int EGUI::ShowMenu(ExState &State, GxView *View) { + char MName[32] = ""; + + if (State.GetStrParam(0, MName, sizeof(MName)) == 0) + return 0; + + View->Parent->PopupMenu(MName); + return 0; +} + +int EGUI::LocalMenu(GxView *View) { + EEventMap *Map = View->GetEventMap(); + const char *MName = 0; + + if (Map) + MName = Map->GetMenu(EM_LocalMenu); + if (MName == 0) + MName = "Local"; + View->Parent->PopupMenu(MName); + return 0; +} + +int EGUI::DesktopSaveAs(ExState &State, GxView *view) { + if (State.GetStrParam(0, DesktopFileName, sizeof(DesktopFileName)) == 0) + if (view->GetFile("Save Desktop", sizeof(DesktopFileName), DesktopFileName, HIST_PATH, GF_SAVEAS) == 0) + return 0; + + if (DesktopFileName[0] != 0) + return SaveDesktop(DesktopFileName); + return 0; +} + +int EGUI::FrameNew() { + GxView *view; + ExModelView *edit; + + if (!multiFrame() && frames) + return 0; + + (void)new EFrame(ScreenSizeX, ScreenSizeY); + assert(frames != 0); + + //frames->SetMenu("Main"); //?? + + view = new GxView(frames); + assert(view != 0); + + (void)new EView(ActiveModel); + assert(ActiveView != 0); + + edit = new ExModelView(ActiveView); + assert(edit != 0); + view->PushView(edit); + frames->Show(); + return 1; +} + +int EGUI::FrameClose(GxView *View) { + assert(frames != 0); + assert(View != 0); + + if (!frames->isLastFrame()) { + deleteFrame(frames); + } else { + if (ExitEditor(ActiveView) == 0) + return 0; + deleteFrame(frames); + } + return 1; +} + +int EGUI::FrameNext(GxView *View) { + if (!frames->isLastFrame()) { + frames->Next->Activate(); + return 1; + } + return 0; +} + +int EGUI::FramePrev(GxView *View) { + if (!frames->isLastFrame()) { + frames->Prev->Activate(); + return 1; + } + return 0; +} + +#ifdef CONFIG_DESKTOP +int EGUI::findDesktop(char *argv[]) { + /* + * Locates the desktop file depending on the load desktop mode flag: + * 0: Try the "current" directory, then the FTE .exe directory (PC) or + * the user's homedir (Unix). Fail if not found (original FTE + * algorithm). + * 1: Try the current directory, then loop {go one directory UP and try} + * If not found, don't load a desktop! + * 2: As above, but asks to save the desktop if one was not found. + * This is called if the desktop is not spec'd on the command line. + */ + switch (LoadDesktopMode) { + default: + //** 0: try curdir then "homedir".. + // fprintf(stderr, "ld: Mode 0\n"); + if (FileExists(DESKTOP_NAME)) + ExpandPath(DESKTOP_NAME, DesktopFileName); + else { + //** Use homedir, +#ifdef UNIX + ExpandPath("~/" DESKTOP_NAME, DesktopFileName); +#else + JustDirectory(argv[0], DesktopFileName); + strcat(DesktopFileName, DESKTOP_NAME); +#endif + } + return FileExists(DesktopFileName); + + case 1: + case 2: + //** Try curdir, then it's owner(s).. + ExpandPath(".", DesktopFileName); + //fprintf(stderr, "ld: Mode 1 (start at %s)\n", DesktopFileName); + + for (;;) { + //** Try current location, + char *pe = DesktopFileName + strlen(DesktopFileName); + Slash(DesktopFileName, 1); // Add appropriate slash + strcat(DesktopFileName, DESKTOP_NAME); + + //fprintf(stderr, "ld: Mode 1 (trying %s)\n", DesktopFileName); + if (FileExists(DesktopFileName)) { + //fprintf(stderr, "ld: Mode 1 (using %s)\n", DesktopFileName); + return 1; + } + + //** Not found. Remove added stuff, then go level UP, + *pe = 0; + + // Remove the current part, + char *p = SepRChr(DesktopFileName); + + if (p == NULL) { + //** No desktop! Set default name in current directory, + ExpandPath(".", DesktopFileName); + Slash(DesktopFileName, 1); + strcat(DesktopFileName, DESKTOP_NAME); + + SaveDesktopOnExit = 0; // Don't save, + return 0; // NOT found!! + } + *p = 0; // Truncate name at last + } + } +} + +void EGUI::DoLoadDesktopOnEntry(int &/*argc*/, char **argv) { + if (DesktopFileName[0] == 0) + findDesktop(argv); + + if (DesktopFileName[0] != 0) { + if (IsDirectory(DesktopFileName)) { + Slash(DesktopFileName, 1); + strcat(DesktopFileName, DESKTOP_NAME); + } + + if (LoadDesktopOnEntry && FileExists(DesktopFileName)) + LoadDesktop(DesktopFileName); + } +} +#endif + +void EGUI::EditorInit() { + SSBuffer = new EBuffer(0, (EModel **)&SSBuffer, "Scrap"); + assert(SSBuffer != 0); + BFI(SSBuffer, BFI_Undo) = 0; // disable undo for clipboard + ActiveModel = 0; +} + +int EGUI::InterfaceInit(int &argc, char **argv) { + if (FrameNew() == 0) + DieError(1, "Failed to create window\n"); + return 0; +} + +#ifdef CONFIG_HISTORY +void EGUI::DoLoadHistoryOnEntry(int &argc, char **argv) { + if (HistoryFileName[0] == 0) { +#ifdef UNIX + ExpandPath("~/.fte-history", HistoryFileName); +#else + JustDirectory(argv[0], HistoryFileName); + strcat(HistoryFileName, "fte.his"); +#endif + } else { + char p[256]; + + ExpandPath(HistoryFileName, p); + if (IsDirectory(p)) { + Slash(p, 1); + strcat(p, HISTORY_NAME); + } + strcpy(HistoryFileName, p); + } + + if (KeepHistory && FileExists(HistoryFileName)) + LoadHistory(HistoryFileName); +} + +void EGUI::DoSaveHistoryOnExit() { + if (KeepHistory && HistoryFileName[0] != 0) + SaveHistory(HistoryFileName); + + // since we are exiting, free history + ClearHistory(); +} +#endif + +int EGUI::CmdLoadFiles(int &argc, char **argv) { + int QuoteNext = 0; + int QuoteAll = 0; + int GotoLine = 0; + int LineNum = 1; + int ColNum = 1; + int ModeOverride = 0; + char Mode[32]; + int LCount = 0; + int ReadOnly = 0; + + for (int Arg = 1; Arg < argc; Arg++) { + if (!QuoteAll && !QuoteNext && (argv[Arg][0] == '-')) { + if (argv[Arg][1] == '-') { + QuoteAll = 1; + } else if (argv[Arg][1] == '!') { + // handled before + } else if (argv[Arg][1] == 'c' || argv[Arg][1] == 'C') { + // ^ + } else if (argv[Arg][1] == 'D' || argv[Arg][1] == 'd') { + // ^ + } else if (argv[Arg][1] == 'H') { + // ^ + } else if (argv[Arg][1] == '+') { + QuoteNext = 1; + } else if (argv[Arg][1] == '#' || argv[Arg][1] == 'l') { + LineNum = 1; + ColNum = 1; + if (strchr(argv[Arg], ',')) { + GotoLine = (2 == sscanf(argv[Arg] + 2, "%d,%d", &LineNum, &ColNum)); + } else { + GotoLine = (1 == sscanf(argv[Arg] + 2, "%d", &LineNum)); + } + // printf("Gotoline = %d, line = %d, col = %d\n", GotoLine, LineNum, ColNum); + } else if (argv[Arg][1] == 'r') { + ReadOnly = 1; + } else if (argv[Arg][1] == 'm') { + if (argv[Arg][2] == 0) { + ModeOverride = 0; + } else { + ModeOverride = 1; + strcpy(Mode, argv[Arg] + 2); + } + } else if (argv[Arg][1] == 'T') { + TagsAdd(argv[Arg] + 2); + } else if (argv[Arg][1] == 't') { + TagGoto(ActiveView, argv[Arg] + 2); + } else { + DieError(2, "Invalid command line option %s", argv[Arg]); + return 0; + } + } else { + char Path[MAXPATH]; + + QuoteNext = 0; + if (ExpandPath(argv[Arg], Path) == 0 && IsDirectory(Path)) { + EModel *m = new EDirectory(cfAppend, &ActiveModel, Path); + assert(ActiveModel != 0 && m != 0); + } else { + if (LCount != 0) + suspendLoads = 1; + if (MultiFileLoad(cfAppend, argv[Arg], + ModeOverride ? Mode : 0, + ActiveView) == 0) { + suspendLoads = 0; + return 0; + } + suspendLoads = 0; + + if (GotoLine) { + if (((EBuffer *)ActiveModel)->Loaded == 0) + ((EBuffer *)ActiveModel)->Load(); + if (GotoLine) { + GotoLine = 0; + ((EBuffer *)ActiveModel)->SetNearPosR(ColNum - 1, LineNum - 1); + } else { + int r, c; + + if (RetrieveFPos(((EBuffer *)ActiveModel)->FileName, r, c) == 1) + ((EBuffer *)ActiveModel)->SetNearPosR(c, r); + } + //ActiveView->SelectModel(ActiveModel); + } + if (ReadOnly) { + ReadOnly = 0; + BFI(((EBuffer *)ActiveModel), BFI_ReadOnly) = 1; + } + } + suspendLoads = 1; + ActiveView->SelectModel(ActiveModel->Next); + suspendLoads = 0; + LCount++; + } + } + EModel *P = ActiveModel; + while (LCount-- > 0) + P = P->Prev; + ActiveView->SelectModel(P); + return 1; +} + +int EGUI::Start(int &argc, char **argv) { + { + int rc; + + rc = GUI::Start(argc, argv); + + if (rc) + return rc; + } + + if (InterfaceInit(argc, argv) != 0) + return 2; + + EditorInit(); + +#ifdef CONFIG_HISTORY + DoLoadHistoryOnEntry(argc, argv); +#endif + +#ifdef CONFIG_DESKTOP + DoLoadDesktopOnEntry(argc, argv); +#endif + + if (CmdLoadFiles(argc, argv) == 0) + return 3; + + if (ActiveModel == 0) { +#ifdef CONFIG_OBJ_DIRECTORY + char Path[MAXPATH]; + + GetDefaultDirectory(0, Path, sizeof(Path)); + EModel *m = new EDirectory(0, &ActiveModel, Path); + assert(ActiveModel != 0 && m != 0); + ActiveView->SwitchToModel(ActiveModel); +#else + Usage(); + return 1; +#endif + } + return 0; +} + +void EGUI::EditorCleanup() { + if (ActiveModel) { + EModel *B, *N, *A; + + B = A = ActiveModel; + do { + N = B->Next; + delete B; + B = N; + } while (B != A); + } + ActiveModel = 0; + + delete SSBuffer; + SSBuffer = 0; + + if (ActiveView) { + EView *BW, *NW, *AW; + + BW = AW = ActiveView; + do { + NW = BW->Next; + delete BW; + BW = NW; + } while (BW != AW); + } + ActiveView = 0; +} + +void EGUI::InterfaceCleanup() { + while (frames) + delete frames; +} + +void EGUI::Stop() { +#ifdef CONFIG_HISTORY + DoSaveHistoryOnExit(); +#endif + + // free macros + if (Macros!=NULL) + { + int i; + + while (CMacros--) + { + free(Macros[CMacros].Name); + + for (i=0; iNext; + delete p; + } + } + + // free event maps + { + EEventMap *em; + + while ((em = EventMaps) != NULL) { + EventMaps = EventMaps->Next; + delete em; + } + } + + // free modes + { + EMode *m; + + while ((m = Modes) != NULL) { + Modes = Modes->fNext; + delete m; + } + } + + // free menus + if (Menus) + { + int mc, c; + + while(MenuCount--) + { + mc = MenuCount; + + free(Menus[mc].Name); + + while(Menus[mc].Count--) + { + c = Menus[mc].Count; + free(Menus[mc].Items[c].Name); + } + + free(Menus[MenuCount].Items); + } + + free(Menus); + + Menus = NULL; + } + + // free completion rexexp filter + { + extern RxNode *CompletionFilter; + + RxFree(CompletionFilter); + } + + // free CRegexp array from o_messages.cpp + { + FreeCRegexp(); + } + + // free configuration file path + { + free(ConfigSourcePath); + ConfigSourcePath = NULL; + } + + EditorCleanup(); + + InterfaceCleanup(); + + GUI::Stop(); +} diff --git a/src/egui.h b/src/egui.h new file mode 100644 index 0000000..69d4f1c --- /dev/null +++ b/src/egui.h @@ -0,0 +1,91 @@ +/* egui.h + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#ifndef __EGUI_H__ +#define __EGUI_H__ + +class EFrame: public GFrame { +public: + EEventMap *CMap; + EModel *CModel; + + EFrame(int XSize, int YSize); + virtual ~EFrame(); + + virtual void Update(); + virtual void UpdateMenu(); +}; + +class EGUI: public GUI { +public: + EKeyMap *ActiveMap; + EKeyMap *OverrideMap; + char CharMap[32]; + + EGUI(int &argc, char **argv, int XSize, int YSize); + virtual ~EGUI(); + + virtual int ExecCommand(GxView *view, int Command, ExState &State); + virtual int ExecMacro(GxView *view, int Macro); + virtual int BeginMacro(GxView *view); + + void SetMsg(char *Msg); + void SetOverrideMap(EKeyMap *aMap, char *ModeName); + void SetMap(EKeyMap *aMap, KeySel *ks); +// void CharEvent(TEvent &Event, char Ch); + + void DispatchKey(GxView *view, TEvent &Event); + void DispatchCommand(GxView *view, TEvent &Event); + + virtual void DispatchEvent(GFrame *frame, GView *view, TEvent &Event); + + int FileCloseX(EView *View, int CreateNew, int XClose = 0); + int FileClose(EView *View, ExState &State); + int FileCloseAll(EView *View, ExState &State); + + int WinNext(GxView *view); + int WinPrev(GxView *view); + + int WinHSplit(GxView *View); + int WinClose(GxView *View); + int WinZoom(GxView *View); + int WinResize(ExState &State, GxView *View); + int ExitEditor(EView *View); + + int FrameNew(); + int FrameClose(GxView *View); + int FrameNext(GxView *View); + int FramePrev(GxView *View); + + int ShowEntryScreen(); + int RunProgram(ExState &State, GxView *view); + int RunProgramAsync(ExState &State, GxView *view); + + int MainMenu(ExState &State, GxView *View); + int ShowMenu(ExState &State, GxView *View); + int LocalMenu(GxView *View); + + int DesktopSaveAs(ExState &State, GxView *View); + + int findDesktop(char *argv[]); + void DoLoadDesktopOnEntry(int &argc, char **argv); + void EditorInit(); + int CmdLoadFiles(int &argc, char **argv); + int InterfaceInit(int &argc, char **argv); + void DoLoadHistoryOnEntry(int &argc, char **argv); + void DoSaveHistoryOnExit(); + + void EditorCleanup(); + void InterfaceCleanup(); + + virtual int Start(int &argc, char **argv); + virtual void Stop(); +}; + +#endif diff --git a/src/feature.h b/src/feature.h new file mode 100644 index 0000000..9f44257 --- /dev/null +++ b/src/feature.h @@ -0,0 +1,93 @@ +/* feature.h + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +/* some stuff does not yet work */ + +#ifndef __FEATURE_H__ +#define __FEATURE_H__ + +#undef CONFIG_EMULATE_VI // todo + +#define CONFIG_CONFIGURABLE +#define CONFIG_MOUSE +#define CONFIG_CLIPBOARD +#define CONFIG_SHELL + +#define CONFIG_MFRAMES +#define CONFIG_MWINDOWS +#define CONFIG_MBUFFERS +#define CONFIG_MENUS +#define CONFIG_SCROLLBARS +#define CONFIG_I_SEARCH +#define CONFIG_I_ASCII +#define CONFIG_HISTORY +#define CONFIG_DESKTOP + +#define CONFIG_BLOCK_STREAM +#define CONFIG_BLOCK_COLUMN +#define CONFIG_BLOCK_LINE +#define CONFIG_IOBLOCKS +#define CONFIG_PRINTING +#define CONFIG_BOOKMARKS +#define CONFIG_WORDWRAP +#define CONFIG_ABBREV +#define CONFIG_TAGS + +#define CONFIG_UNDOREDO +#define CONFIG_REGEXPS +#define CONFIG_FOLDS + +#undef CONFIG_OBJ_HEXEDIT // todo +#undef CONFIG_OBJ_VIEWER // todo +#define CONFIG_OBJ_LIST +#define CONFIG_OBJ_FILE + +#ifdef CONFIG_OBJ_LIST +#define CONFIG_OBJ_DIRECTORY +#define CONFIG_OBJ_ROUTINE +#define CONFIG_OBJ_BUFFERS +#define CONFIG_OBJ_MESSAGES +#endif + +#define CONFIG_SYNTAX_HILIT +#define CONFIG_WORD_HILIT + +#ifdef CONFIG_SYNTAX_HILIT +#define CONFIG_HILIT_C +#define CONFIG_HILIT_REXX +#define CONFIG_HILIT_HTML +#define CONFIG_HILIT_PERL +#define CONFIG_HILIT_ADA +#define CONFIG_HILIT_MAKE +#define CONFIG_HILIT_DIFF +#define CONFIG_HILIT_MERGE +#define CONFIG_HILIT_IPF +#define CONFIG_HILIT_MSG +#define CONFIG_HILIT_SH +#define CONFIG_HILIT_PASCAL +#define CONFIG_HILIT_TEX +#define CONFIG_HILIT_FTE +#define CONFIG_HILIT_CATBS +#define CONFIG_HILIT_SIMPLE +#endif + +#if defined(CONFIG_HILIT_C) +#define CONFIG_INDENT_C +#endif + +#if defined(CONFIG_HILIT_SIMPLE) +#define CONFIG_INDENT_SIMPLE +#endif + +#if defined(CONFIG_HILIT_REXX) +#define CONFIG_INDENT_REXX +#endif + +#define CONFIG_I_COMPLETE +#endif diff --git a/src/fnmatch.h b/src/fnmatch.h new file mode 100644 index 0000000..eeaee7f --- /dev/null +++ b/src/fnmatch.h @@ -0,0 +1,84 @@ +/* Copyright (C) 1991, 92, 93, 96, 97, 98 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#ifndef _FNMATCH_H +#define _FNMATCH_H 1 + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined __cplusplus || (defined __STDC__ && __STDC__) || defined WINDOWS32 +# if !defined __GLIBC__ || !defined __P +# undef __P +# define __P(protos) protos +# endif +#else /* Not C++ or ANSI C. */ +# undef __P +# define __P(protos) () +/* We can get away without defining `const' here only because in this file + it is used only inside the prototype for `fnmatch', which is elided in + non-ANSI C where `const' is problematical. */ +#endif /* C++ or ANSI C. */ + +#ifndef const +# if (defined __STDC__ && __STDC__) || defined __cplusplus +# define __const const +# else +# define __const +# endif +#endif + +/* We #undef these before defining them because some losing systems + (HP-UX A.08.07 for example) define these in . */ +#undef FNM_PATHNAME +#undef FNM_NOESCAPE +#undef FNM_PERIOD + +/* Bits set in the FLAGS argument to `fnmatch'. */ +#define FNM_PATHNAME (1 << 0) /* No wildcard can ever match `/'. */ +#define FNM_NOESCAPE (1 << 1) /* Backslashes don't quote special chars. */ +#define FNM_PERIOD (1 << 2) /* Leading `.' is matched only explicitly. */ + +#if !defined _POSIX_C_SOURCE || _POSIX_C_SOURCE < 2 || defined _GNU_SOURCE +# define FNM_FILE_NAME FNM_PATHNAME /* Preferred GNU name. */ +# define FNM_LEADING_DIR (1 << 3) /* Ignore `/...' after a match. */ +# define FNM_CASEFOLD (1 << 4) /* Compare without regard to case. */ +#endif + +/* Value returned by `fnmatch' if STRING does not match PATTERN. */ +#define FNM_NOMATCH 1 + +/* This value is returned if the implementation does not support + `fnmatch'. Since this is not the case here it will never be + returned but the conformance test suites still require the symbol + to be defined. */ +#ifdef _XOPEN_SOURCE +# define FNM_NOSYS (-1) +#endif + +/* Match STRING against the filename pattern PATTERN, + returning zero if it matches, FNM_NOMATCH if not. */ +extern int fnmatch __P ((__const char *__pattern, __const char *__string, + int __flags)); + +#ifdef __cplusplus +} +#endif + +#endif /* fnmatch.h */ diff --git a/src/fte-bcc2.mak b/src/fte-bcc2.mak new file mode 100644 index 0000000..62b8eb1 --- /dev/null +++ b/src/fte-bcc2.mak @@ -0,0 +1,72 @@ +LIBDIR = \BCOS2\LIB +INCDIR = \BCOS2\INCLUDE + +.AUTODEPEND + +DEFINES=-DOS2 -DBCPP -DHEAPWALK + +DEBUG = +#DEBUG=-v + +INIT = $(LIBDIR)\c02.obj + +CC = bcc +LD = tlink +CCFLAGS = $(DEFINES) -L$(LIBDIR) -I$(INCDIR) -H=fte.CSM \ + -k- -sm -K -w -w-par -Ot -RT- -xd- -x- -vi- -d -a -y $(DEBUG) + +LDFLAGS = -L$(LIBDIR) $(DEBUG) -s -Toe -Oc -B:0x10000 +OEXT=obj + +!include objs.inc + +.cpp.$(OEXT): + $(CC) $(CCFLAGS) -c {$< } + +.c.$(OEXT): + $(CC) $(CCFLAGS) -c {$< } + +all: cfte.exe fte.exe ftepm.exe clipserv.exe cliputil.exe + +defcfg.cnf: defcfg.fte cfte.exe + cfte defcfg.fte defcfg.cnf + +defcfg.h: defcfg.cnf bin2c.exe + bin2c defcfg.cnf >defcfg.h + +c_config.obj: defcfg.h + +bin2c.exe: bin2c.cpp + $(CC) $(CCFLAGS) bin2c.cpp + +cfte.exe: $(CFTE_OBJS) + $(LD) @&&| + $(LDFLAGS) $(INIT) $**,cfte.exe,cfte.map,os2 c2mt,cfte.def +| + +fte.exe: $(OBJS) $(VIOOBJS) + $(LD) @&&| + $(LDFLAGS) $(INIT) $**,fte.exe,fte.map,os2 c2mt,fte.def +| + +ftepm.exe:: $(OBJS) $(PMOBJS) + $(LD) @&&| + $(LDFLAGS) $(INIT) $**,ftepm.exe,ftepm.map,c2mt os2,ftepm.def +| + rc -i $(INCDIR) ftepm.rc ftepm.exe + +clipserv.exe: clipserv.obj + $(LD) @&&| + $(LDFLAGS) $(INIT) $**,clipserv.exe,clipserv.map,c2mt os2,clipserv.def +| + +cliputil.exe: cliputil.obj clip_vio.obj + $(LD) @&&| + $(LDFLAGS) $(INIT) $**,cliputil.exe,cliputil.map,c2mt os2,cliputil.def +| + +ftepm.exe:: ftepm.res + rc ftepm.res ftepm.exe + +ftepm.res: ftepm.rc pmdlg.rc + rc -i $(INCDIR) -r ftepm.rc diff --git a/src/fte-bcc5.mak b/src/fte-bcc5.mak new file mode 100644 index 0000000..2d729a4 --- /dev/null +++ b/src/fte-bcc5.mak @@ -0,0 +1,63 @@ +# +# FTE makefile for use with Borland C++ 5.5.x/C++Builder 5 +# +# The author, Jon Svendsen, explicitly places this module +# in the Public Domain +# +# Assumes compiler-native includes to be in $(MAKEDIR)\..\Include +# and libraries in $(MAKEDIR)\..\Libs +# $(MAKEDIR) is set by Borland make and is the location of your make.exe +# + +INCDIR = $(MAKEDIR)\..\Include +LIBDIR = $(MAKEDIR)\..\Lib + +OPTIMIZE = -O2 + +CC = bcc32 +LD = ilink32 + +OEXT = obj + +DEFS = -DNT -DNTCONSOLE -DBCPP + +CCFLAGS = $(OPTIMIZE) -w-aus -w-par -tWC $(DEFS) -I$(INCDIR) +LDFLAGS = -ap -Tpe -c -x -Gn -L$(LIBDIR) -j$(LIBDIR) +LDOBJS = c0x32.obj +LDLIBS = import32.lib cw32.lib + +!include objs.inc + +.cpp.$(OEXT): + $(CC) $(CCFLAGS) -c {$< } + +.c.$(OEXT): + $(CC) $(CCFLAGS) -c {$< } + +all: cfte.exe fte.exe + +defcfg.cnf: defcfg.fte cfte.exe + cfte defcfg.fte defcfg.cnf + +defcfg.h: defcfg.cnf bin2c.exe + bin2c defcfg.cnf >defcfg.h + +c_config.obj: defcfg.h + +bin2c.exe: bin2c.obj + $(LD) $(LDFLAGS) $(LDOBJS) bin2c.obj,$< ,,$(LDLIBS) ,, + +cfte.exe: $(CFTE_OBJS) + $(LD) $(LDFLAGS) $(LDOBJS) $(CFTE_OBJS),$< ,,$(LDLIBS) ,, + +fte.exe: $(OBJS) $(NTOBJS) + $(LD) $(LDFLAGS) $(LDOBJS) $(OBJS) $(NTOBJS),$< ,,$(LDLIBS) ,, + +clean: + del *.$(OEXT) + del *.tds + del fte.exe + del cfte.exe + del bin2c.exe + del defcfg.h + del defcfg.cnf diff --git a/src/fte-cygwin-xf86.mak b/src/fte-cygwin-xf86.mak new file mode 100644 index 0000000..e6fa373 --- /dev/null +++ b/src/fte-cygwin-xf86.mak @@ -0,0 +1,103 @@ +# versions of FTE to build + +# Versions: +# xfte - using XLib (the most stable) + +TARGETS = xfte + +PRIMARY = xfte + +# Comment or uncoment this two flags below if +# you want to use: + +# Keyboard remaping by XFTE +#REMAPFLAG = -DUSE_HARD_REMAP + +# Drawing fonts with locale support +XMBFLAG = -DUSE_XMB + +# System X11R6 is compiled with X_LOCALE +#SYSTEM_X_LOCALE = -DX_LOCALE + +I18NOPTIONS = $(XMBFLAG) $(REMAPFLAG) $(SYSTEM_X_LOCALE) + +# Optionally, you can define: +# -DDEFAULT_INTERNAL_CONFIG to use internal config by default +# -DUSE_XTINIT to use XtInitialize on init +# -DFTE_NO_LOGGING to completely disable trace logging +APPOPTIONS = -DDEFAULT_INTERNAL_CONFIG + +#gcc/g++ +COPTIONS = -Wall -Wpointer-arith -Wconversion -Wwrite-strings \ + -Wmissing-prototypes -Wmissing-declarations -Winline + +#CC = g++ +#LD = g++ +# try this for smaller/faster code and less dependencies +CC = g++ -fno-rtti -fno-exceptions +LD = g++ -fno-rtti -fno-exceptions + + +####################################################################### +# Linux +UOS = -DLINUX +XINCDIR = -I/usr/X11R6/include +XLIBDIR = -L/usr/X11R6/lib -lstdc++ +SOCKETLIB = -lwsock32 -liberty + +####################################################################### + +LIBDIR = +INCDIR = + +#OPTIMIZE = -g # -O -g +OPTIMIZE = -O2 +#OPTIMIZE = -O2 -s + +CCFLAGS = $(OPTIMIZE) $(I18NOPTIONS) $(APPOPTIONS) $(COPTIONS) -DUNIX $(UOS) \ + $(INCDIR) $(XINCDIR) +LDFLAGS = $(OPTIMIZE) $(LIBDIR) $(XLIBDIR) + +OEXT = o + +.SUFFIXES: .cpp .o + +include objs.inc + +# Need -lXt below if USE_XTINIT is defined +XLIBS = -lX11 $(SOCKETLIB) + +.cpp.o: + $(CC) $(CCFLAGS) -c $< + +.c.o: + $(CC) $(CCFLAGS) -c $< + + +all: cfte $(TARGETS) +#rm -f fte ; ln -s $(PRIMARY) fte + +cfte: cfte.o s_files.o + $(LD) $(LDFLAGS) cfte.o s_files.o -o cfte + +c_config.o: defcfg.h + +defcfg.h: defcfg.cnf + perl mkdefcfg.pl defcfg.h + +#DEFAULT_FTE_CONFIG = simple.fte +DEFAULT_FTE_CONFIG = defcfg.fte +#DEFAULT_FTE_CONFIG = defcfg2.fte +#DEFAULT_FTE_CONFIG = ../config/main.fte + +defcfg.cnf: $(DEFAULT_FTE_CONFIG) cfte + ./cfte $(DEFAULT_FTE_CONFIG) defcfg.cnf + +xfte: $(OBJS) $(XOBJS) + $(LD) $(LDFLAGS) $(OBJS) $(XOBJS) $(XLIBS) -o xfte + +compkeys: compkeys.o + $(LD) $(LDFLAGS) compkeys.o -o compkeys + +clean: + rm -f core *.o $(TARGETS) defcfg.h defcfg.cnf cfte fte vfte compkeys diff --git a/src/fte-dj2.mak b/src/fte-dj2.mak new file mode 100644 index 0000000..49096a0 --- /dev/null +++ b/src/fte-dj2.mak @@ -0,0 +1,54 @@ +# MSDOS makefile for djgpp v2 and GNU make +# Contributed by Markus F.X.J. Oberhumer + +CC = gxx +LD = gxx + +INCDIR = +LIBDIR = + +#OPTIMIZE = -g +OPTIMIZE = -O2 -fno-strength-reduce -fomit-frame-pointer -s + +CCFLAGS = -x c++ -fconserve-space $(OPTIMIZE) $(INCDIR) +CCFLAGS += -Wall -W -Wsynth -Wno-unused +CCFLAGS += -DDOSP32 -D__32BIT__ +LDFLAGS = $(OPTIMIZE) $(LIBDIR) + +OEXT=o + +.SUFFIXES: .cpp .$(OEXT) + +include objs.inc +CFTE_OBJS += port.$(OEXT) +CFTE_OBJS += memicmp.$(OEXT) + +.cpp.$(OEXT): + $(CC) $(CCFLAGS) -c $< + +.c.$(OEXT): + $(CC) $(CCFLAGS) -c $< + +.PHONY: default all clean + +default all: cfte.exe fte.exe + +clean: + -$(RM) *.o bin2c.exe cfte.exe fte.exe defcfg.cnf defcfg.h + +cfte.exe: $(CFTE_OBJS) + $(LD) $(LDFLAGS) $(CFTE_OBJS) -o $@ + +defcfg.cnf: defcfg.fte cfte.exe + cfte defcfg.fte defcfg.cnf + +defcfg.h: defcfg.cnf bin2c.exe + bin2c defcfg.cnf >defcfg.h + +bin2c.exe: bin2c.cpp + $(CC) $(CCFLAGS) $< -o $@ + +c_config.$(OEXT): defcfg.h + +fte.exe: $(OBJS) $(DOSP32OBJS) + $(LD) $(LDFLAGS) $^ -o $@ diff --git a/src/fte-emx.mak b/src/fte-emx.mak new file mode 100644 index 0000000..cbd39b6 --- /dev/null +++ b/src/fte-emx.mak @@ -0,0 +1,80 @@ +INCDIR = +LIBDIR = + +#OPTIMIZE = -g +OPTIMIZE = -O -s +#OPTIMIZE = -O2 -s + +MT = -Zmt + +CC = gcc +LD = gcc + +#XTYPE = -Zomf +#XLTYPE = -Zsys -Zlinker /map -Zlinker /runfromvdm # -Zomf +#OEXT=obj +OEXT=o + +#DEFS = -DDEBUG_EDITOR -DCHECKHEAP +#LIBS = -lmalloc1 +#DEFS = -DDEBUG_EDITOR -DDBMALLOC -I/src/dbmalloc +#LIBS = -L/src/dbmalloc -ldbmalloc +LIBS = -lstdcpp + +DEFS=-DINCL_32 #-DUSE_OS2_TOOLKIT_HEADERS + +CCFLAGS = $(OPTIMIZE) $(MT) $(XTYPE) -x c++ -Wall -DOS2 $(DEFS) $(INCDIR) -pipe +LDFLAGS = $(OPTIMIZE) $(MT) -Zmap $(XLTYPE) $(LIBDIR) + +.SUFFIXES: .cpp .$(OEXT) + +include objs.inc + +.cpp.$(OEXT): + $(CC) $(CCFLAGS) -c $< + +.c.$(OEXT): + $(CC) $(CCFLAGS) -c $< + +all: cfte.exe fte.exe ftepm.exe clipserv.exe cliputil.exe + +clipserv.exe: clipserv.$(OEXT) clipserv.def + $(LD) $(LDFLAGS) clipserv.$(OEXT) clipserv.def -o clipserv.exe $(LIBS) + +cliputil.exe: cliputil.$(OEXT) clip_vio.$(OEXT) cliputil.def + $(LD) $(LDFLAGS) cliputil.$(OEXT) clip_vio.$(OEXT) cliputil.def -o cliputil.exe $(LIBS) + +cfte.exe: $(CFTE_OBJS) cfte.def + $(LD) $(LDFLAGS) $(CFTE_OBJS) cfte.def -o cfte.exe $(LIBS) + +defcfg.cnf: defcfg.fte cfte.exe + cfte defcfg.fte defcfg.cnf + +defcfg.h: defcfg.cnf bin2c.exe + bin2c defcfg.cnf >defcfg.h + +bin2c.exe: bin2c.cpp + $(CC) $(CCFLAGS) bin2c.cpp -o bin2c.exe + +c_config.$(OEXT): defcfg.h + +fte.exe: $(OBJS) $(VIOOBJS) fte.def + $(LD) $(LDFLAGS) $(OBJS) $(VIOOBJS) fte.def -o fte.exe $(LIBS) + +ftepm.res: ftepm.rc pmdlg.rc bmps/*.bmp + rc -r -i \emx\include ftepm.rc ftepm.res + +ftepm.exe: $(OBJS) $(PMOBJS) ftepm.def ftepm.res + $(LD) $(LDFLAGS) $(OBJS) $(PMOBJS) ftepm.def ftepm.res -o ftepm.exe $(LIBS) + +fte.cnf: cfte.exe + cfte ..\config\main.fte fte.cnf + +#rc -i \emx\include ftepm.rc ftepm.exe + +#ftepm.exe:: ftepm.res +# rc ftepm.res ftepm.exe + +distro: ftepm.exe fte.exe fte.cnf cfte.exe clipserv.exe cliputil.exe + zip ../fte-os2.zip ftepm.exe fte.exe fte.cnf cfte.exe clipserv.exe cliputil.exe + (cd .. && zip -r fte-config.zip Artistic doc config) diff --git a/src/fte-mngw.mak b/src/fte-mngw.mak new file mode 100644 index 0000000..926d7d8 --- /dev/null +++ b/src/fte-mngw.mak @@ -0,0 +1,62 @@ +# +# FTE makefile for use with the MinGW toolchain +# +# Please note that the common GNU Make 3.77 port for MinGW is broken +# and does not process this makefile correctly . Get a working Make 3.79.1 +# from http://www.nextgeneration.dk/gnu/ +# +# The author, Jon Svendsen, explicitly places this module +# in the Public Domain +# + +INCDIR = +LIBDIR = + +OPTIMIZE = -O -s + +MT = -Zmt + +CC = g++ +LD = g++ + +# uncomment this if you don't have fileutils installed +# RM = del + +OEXT=o + +DEFS=-DNT -DNTCONSOLE -DMINGW + +CCFLAGS = $(OPTIMIZE) -x c++ -Wall $(DEFS) $(INCDIR) -pipe +LDFLAGS = $(OPTIMIZE) $(LIBDIR) -Wl,-static + +.SUFFIXES: .cpp .$(OEXT) + +include objs.inc + +.cpp.$(OEXT): + $(CC) $(CCFLAGS) -c $< + +.c.$(OEXT): + $(CC) $(CCFLAGS) -c $< + +all: cfte.exe fte.exe + +cfte.exe: $(CFTE_OBJS) + $(LD) $(LDFLAGS) $(CFTE_OBJS) -o cfte.exe $(LIBS) + +defcfg.cnf: defcfg.fte cfte.exe + -"./cfte.exe" defcfg.fte defcfg.cnf + +defcfg.h: defcfg.cnf bin2c.exe + -"./bin2c.exe" defcfg.cnf >defcfg.h + +bin2c.exe: bin2c.cpp + $(CC) $(CCFLAGS) bin2c.cpp -o bin2c.exe + +c_config.$(OEXT): defcfg.h + +fte.exe: $(OBJS) $(NTOBJS) + -$(LD) $(LDFLAGS) $(OBJS) $(NTOBJS) -o fte.exe $(LIBS) + +clean: + -$(RM) fte.exe cfte.exe bin2c.exe defcfg.cnf defcfg.h $(OBJS) $(NTOBJS) $(CFTE_OBJS) \ No newline at end of file diff --git a/src/fte-msvc.mak b/src/fte-msvc.mak new file mode 100644 index 0000000..a720427 --- /dev/null +++ b/src/fte-msvc.mak @@ -0,0 +1,71 @@ +INCDIR = +LIBDIR = + +OPTIMIZE = /O2 /MT +#OPTIMIZE = /Zi /Od /MTd + +#DEBUG = -DMSVCDEBUG + +CC = cl +LD = cl + +OEXT=obj + +#APPOPTIONS = -DDEFAULT_INTERNAL_CONFIG +#/Fm /GF /J +CCFLAGS = $(OPTIMIZE) -DNT -DNTCONSOLE -DMSVC $(INCDIR) /DWIN32 /D_CONSOLE /GX \ + $(APPOPTIONS) $(DEBUG)\ + /nologo /W3 /J # /YX +LDFLAGS = $(OPTIMIZE) $(LIBDIR) /nologo + +.SUFFIXES: .cpp .$(OEXT) + +!include objs.inc + +.cpp.$(OEXT): + $(CC) $(CCFLAGS) -c $< + +.c.$(OEXT): + $(CC) $(CCFLAGS) -c $< + +all: cfte.exe fte.cnf fte.exe + +clean: + -del bin2c.exe + -del bin2c.pdb + -del cfte.exe + -del cfte.pdb + -del cfte.exp + -del cfte.lib + -del defcfg.cnf + -del defcfg.h + -del fte.cnf + -del fte.exe + -del fte.his + -del fte.pdb + -del vc60.pdb + -del *.obj + +cfte.exe: $(CFTE_OBJS) cfte.def + $(LD) $(LDFLAGS) /Fecfte.exe $(CFTE_OBJS) cfte.def + +defcfg.cnf: defcfg.fte cfte.exe + cfte defcfg.fte defcfg.cnf + +defcfg.h: defcfg.cnf bin2c.exe + bin2c defcfg.cnf >defcfg.h + +fte.cnf: ..\config\* cfte.exe + cfte ..\config\main.fte fte.cnf + +bin2c.exe: bin2c.cpp + $(CC) $(CCFLAGS) $(LDFLAGS) /Febin2c.exe bin2c.cpp + +c_config.$(OEXT): defcfg.h + +fte.exe: $(OBJS) $(NTOBJS) + $(LD) $(LDFLAGS) /Fefte.exe $(OBJS) $(NTOBJS) user32.lib + +distro: fte.exe fte.cnf cfte.exe + zip ../fte-nt.zip fte.exe fte.cnf cfte.exe + diff --git a/src/fte-unix.mak b/src/fte-unix.mak new file mode 100644 index 0000000..4535c5f --- /dev/null +++ b/src/fte-unix.mak @@ -0,0 +1,207 @@ +# versions of FTE to build + +# Versions: +# xfte - using XLib (the most stable) + +# vfte - for Linux console directly (with limitations, see con_linux.cpp) + +TARGETS = xfte vfte sfte +#TARGETS = xfte + +PRIMARY = xfte + +# Comment or uncoment this two flags below if +# you want to use: + +# Keyboard remaping by XFTE +#REMAPFLAG = -DUSE_HARD_REMAP + +# Drawing fonts with locale support +XMBFLAG = -DUSE_XMB + +# System X11R6 is compiled with X_LOCALE +#SYSTEM_X_LOCALE = -DX_LOCALE + +I18NOPTIONS = $(XMBFLAG) $(REMAPFLAG) $(SYSTEM_X_LOCALE) + +# Optionally, you can define: +# -DDEFAULT_INTERNAL_CONFIG to use internal config by default +# -DUSE_XTINIT to use XtInitialize on init +# -DFTE_NO_LOGGING to completely disable trace logging +APPOPTIONS = -DDEFAULT_INTERNAL_CONFIG + +#gcc/g++ +COPTIONS = -Wall -Wpointer-arith -Wconversion -Wwrite-strings \ + -Wmissing-prototypes -Wmissing-declarations -Winline + +#CC = g++ +#LD = g++ +# try this for smaller/faster code and less dependencies +CC = g++ -fno-rtti -fno-exceptions +LD = gcc -fno-rtti -fno-exceptions + + +# choose your os here + +####################################################################### +# Linux +UOS = -DLINUX +XLIBDIR = -L/usr/X11R6/lib -lstdc++ + +####################################################################### +# HP/UX +#UOS = -DHPUX -D_HPUX_SOURCE -DCAST_FD_SET_INT +#UOS = -DHPUX -D_HPUX_SOURCE + +#CC = CC +a1 +#LD = CC +#CC = aCC +#LD = aCC + +#XLIBDIR = -L/usr/lib/X11R6 + +#XINCDIR = -I/usr/include/X11R5 +#XLIBDIR = -L/usr/lib/X11R5 + +#MINCDIR = -I/usr/include/Motif1.2 +#MLIBDIR = -L/usr/lib/Motif1.2 + +SINCDIR = -I/usr/include/slang + +####################################################################### +# AIX +#UOS = -DAIX -D_BSD_INCLUDES + +#CC = xlC +#LD = xlC +#COPTIONS = +#TARGETS = xfte + +####################################################################### +# Irix +# missing fnmatch, but otherwise ok (tested only on 64bit) +# 6.x has fnmatch now ;-) +# uncomment below to use SGI CC compiler +#UOS = -DIRIX +#CC = CC +#LD = CC +#COPTIONS = -xc++ + +####################################################################### +# SunOS (Solaris) +#UOS = -DSUNOS +#CC = CC -noex +#LD = CC -noex +#COPTIONS = +#XINCDIR = -I/usr/openwin/include +#XLIBDIR = -L/usr/openwin/lib + +####################################################################### +# for SCO CC +# +# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +# If you have problems with the program "cfte" +# try to compile this program without optimalization -O2 +# use just -O +# +#UOS = -DSCO +#CC = CC -b elf +#LD = $(CC) +#XLIBDIR = -L/usr/X11R6/lib +#SOCKETLIB = -lsocket +#COPTIONS = +.cpp + +####################################################################### +# NCR +#CC = cc -Hnocopyr +#LD = cc -Hnocopyr +#COPTIONS = -w3 +#UOS = -DNCR +#XINCDIR = -I../../include +#SOCKETLIB = -lsocket -lnsl -lc -lucb + +####################################################################### + +#QTDIR = /users/markom/qt +#QLIBDIR = -L$(QTDIR)/lib +#QINCDIR = -I$(QTDIR)/include +#QINCDIR = -I/usr/include/qt + +MOC = moc + +LIBDIR = +INCDIR = + +#OPTIMIZE = -g # -O -g +OPTIMIZE = -O2 +#OPTIMIZE = -O2 -s + +CCFLAGS = $(OPTIMIZE) $(I18NOPTIONS) $(APPOPTIONS) $(COPTIONS) -DUNIX $(UOS) $(INCDIR) $(XINCDIR) $(QINCDIR) $(MINCDIR) $(SINCDIR) +LDFLAGS = $(OPTIMIZE) $(LIBDIR) $(XLIBDIR) $(QLIBDIR) $(MLIBDIR) + +OEXT = o + +.SUFFIXES: .cpp .o .moc + +include objs.inc + +# Need -lXt below if USE_XTINIT is defined +XLIBS = -lX11 $(SOCKETLIB) +VLIBS = -lgpm -lncurses +# -ltermcap outdated by ncurses +SLIBS = -lslang +QLIBS = -lqt +#MLIBS = -lXm -lXp -lXt -lXpm -lXext + +.cpp.o: + $(CC) $(CCFLAGS) -c $< + +.c.o: + $(CC) $(CCFLAGS) -c $< + +.cpp.moc: + $(MOC) $< -o $@ + +all: cfte $(TARGETS) +#rm -f fte ; ln -s $(PRIMARY) fte + +cfte: cfte.o s_files.o + $(LD) $(LDFLAGS) cfte.o s_files.o -o cfte + +c_config.o: defcfg.h + +defcfg.h: defcfg.cnf + perl mkdefcfg.pl defcfg.h + +#DEFAULT_FTE_CONFIG = simple.fte +DEFAULT_FTE_CONFIG = defcfg.fte +#DEFAULT_FTE_CONFIG = defcfg2.fte +#DEFAULT_FTE_CONFIG = ../config/main.fte + +defcfg.cnf: $(DEFAULT_FTE_CONFIG) cfte + ./cfte $(DEFAULT_FTE_CONFIG) defcfg.cnf + +xfte: $(OBJS) $(XOBJS) + $(LD) $(LDFLAGS) $(OBJS) $(XOBJS) $(XLIBS) -o xfte + +#qfte: g_qt.moc g_qt_dlg.moc $(OBJS) $(QOBJS) +# $(LD) $(LDFLAGS) $(OBJS) $(QOBJS) $(QLIBS) $(XLIBS) -o qfte + +vfte: $(OBJS) $(VOBJS) + $(LD) $(LDFLAGS) $(OBJS) $(VOBJS) $(VLIBS) -o vfte + +sfte: $(OBJS) $(SOBJS) compkeys + $(LD) $(LDFLAGS) $(OBJS) $(SOBJS) $(SLIBS) -o sfte + +compkeys: compkeys.o + $(LD) $(LDFLAGS) compkeys.o -o compkeys + +#mfte: $(OBJS) $(MOBJS) +# $(LD) $(LDFLAGS) $(OBJS) $(MOBJS) $(MLIBS) $(XLIBS) -o mfte + +g_qt.obj: g_qt.moc + +g_qt_dlg.obj: g_qt_dlg.moc + +clean: + rm -f core *.o $(TARGETS) defcfg.h defcfg.cnf cfte fte vfte compkeys diff --git a/src/fte-vag.mak b/src/fte-vag.mak new file mode 100644 index 0000000..c0d45af --- /dev/null +++ b/src/fte-vag.mak @@ -0,0 +1,176 @@ +# +# +# Makefile for VisualAge C++ version 3.00 +# +# + +EXE = + +OEXT = obj + +DEBUG = 0 +#DEBUG = 1 + +CC = icc +LINK = ilink +RC = rc +VOID = echo > NUL + +!if $(DEBUG) +C_FLAGS = /Ti /Tx +!else +C_FLAGS = /O /Gs- +!endif +C_OPTIONS = /Q /Tl /G4 /Gm+ /DOS2 /DINCL_32 $(C_FLAGS) + +!if $(DEBUG) +CPP_FLAGS = /Ti /Tm /Tx +!else +CPP_FLAGS = /O /Gs- +!endif +CPP_OPTIONS = /Q /G4 /Gm+ /DOS2 /DINCL_32 $(CPP_FLAGS) + +!if $(DEBUG) +L_FLAGS = /DEBUG /DBGPACK +!else +L_FLAGS = /EXEPACK:2 /PACKC /PACKD /OPTF +!endif +L_OPTIONS = /BASE:0x010000 /EXEC /NOE /NOLOGO $(L_FLAGS) + +RC_OPT = -n + +C_SRC = +C_H = +CPP_SRC = +CPP_HPP = + +!include objs.inc + +RES = + +LIBS = +HLIB = + +DEF = + + +.SUFFIXES: +.SUFFIXES: .cpp .rc + +all: cfte.exe fte.exe ftepm.exe clipserv.exe cliputil.exe fte.cnf + +clean: + -del bin2c.exe + -del bin2c.map + -del cfte.exe + -del cfte.map + -del clipserv.exe + -del clipserv.map + -del cliputil.exe + -del cliputil.map + -del defcfg.cnf + -del defcfg.h + -del fte.cnf + -del fte.exe + -del fte.his + -del fte.map + -del ftepm.exe + -del ftepm.map + -del ftepm.res + -del *.obj + +clipserv.exe: clipserv.$(OEXT) clipserv.def + $(VOID) <defcfg.h + +fte.cnf: ..\config\* cfte.exe + cfte ..\config\main.fte fte.cnf + +bin2c.obj: bin2c.cpp + +bin2c.exe: bin2c.obj + $(VOID) <defcfg.h + +defcfg.cnf: defcfg.fte cfte + cfte defcfg.fte defcfg.cnf + +xfte: $(OBJS) $(XOBJS) + $(LD) $(LDFLAGS) $(OBJS) $(XOBJS) $(XLIBS) -o xfte + +qfte: g_qt.moc g_qt_dlg.moc $(OBJS) $(QOBJS) + $(LD) $(LDFLAGS) $(OBJS) $(QOBJS) $(QLIBS) $(XLIBS) -o qfte + +vfte: $(OBJS) $(VOBJS) + $(LD) $(LDFLAGS) $(OBJS) $(VOBJS) $(VLIBS) -o vfte + +mfte: $(OBJS) $(MOBJS) + $(LD) $(LDFLAGS) $(OBJS) $(MOBJS) $(MLIBS) $(XLIBS) -o mfte + +g_qt.obj: g_qt.moc + +g_qt_dlg.obj: g_qt_dlg.moc + +clean: + rm -f *.o $(TARGETS) defcfg.h defcfg.cnf cfte fte diff --git a/src/fte-xwin.mak b/src/fte-xwin.mak new file mode 100644 index 0000000..a6ff9b1 --- /dev/null +++ b/src/fte-xwin.mak @@ -0,0 +1,246 @@ +# fte-unix.make modified to be generic enough to work with WINNT or UNIX + +# versions of FTE to build + +# Versions: +# xfte - using XLib (the most stable) + +# vfte - for Linux console directly (with limitations, see con_linux.cpp) + +#WINNT +ESUF=.exe +OEXT=obj +OUTFLAG = -out: +OUTEXEFLAG = /Fe + +#UNIX +#ESUF= +#OEXT=o +#OUTFLAG = -o +#OUTEXEFLAG = -o +# -o must have a space after it above + +.SUFFIXES: .cpp .$(OEXT) + +TARGETS = xfte$(ESUF) +#TARGETS = vfte$(ESUF) xfte$(ESUF) + +PRIMARY = xfte$(ESUF) + +# Comment or uncoment this two flags below if +# you want to use: + +# Keyboard remaping by XFTE +#REMAPFLAG = -DUSE_HARD_REMAP + +# Drawing fonts with locale support +#XMBFLAG = -DUSE_XMB + +# System X11R6 is compiled with X_LOCALE +#SYSTEM_X_LOCALE = -DX_LOCALE + +I18NOPTIONS = $(XMBFLAG) $(REMAPFLAG) $(SYSTEM_X_LOCALE) + +# Optionally, you can define: +# -DDEFAULT_INTERNAL_CONFIG to use internal config by default +# -DUSE_XTINIT to use XtInitialize on init +APPOPTIONS = -DDEFAULT_INTERNAL_CONFIG -DUSE_XTINIT + +#gcc/g++ +#COPTIONS = -Wall -Wpointer-arith -Wconversion -Wwrite-strings \ +# -Wmissing-prototypes -Wmissing-declarations -Winline + +#CC = g++ +#LD = g++ +# try this for smaller/faster code and less dependencies +#CC = g++ -fno-rtti -fno-exceptions +#LD = gcc -fno-rtti -fno-exceptions + +# choose your os here + +####################################################################### +#MSVC/EXCEED XDK +X_BASE = C:\win32app\Exceed\xdk + +X_LIBS = -LIBPATH:$(X_BASE)\lib \ + HCLXm.lib HCLMrm.lib HCLXmu.lib HCLXt.lib Xlib.lib hclshm.lib xlibcon.lib \ + +# Xm.lib Mrm.lib Xmu.lib Xt.lib Xlib.lib hclshm.lib xlibcon.lib + +XINCDIR = -I:$(X_BASE)\include + +#optimize +#OPTIMIZE = /Ox -DNDEBUG + +#debug +#OPTIMIZE = /Od /Zi -D_DEBUG +#LDOPTIMIZE = /DEBUG + +CC = cl +LD = link + +CCFLAGS = $(OPTIMIZE) -DNT -DMSVC $(INCDIR) -DWIN32 -D_CONSOLE -DWINHCLX \ + -nologo -W3 -J -DNONXP -DWINNT -D_X86_ -MD -Op -W3 -QIfdiv -GX \ + $(XINCDIR) +LDFLAGS = $(LDOPTIMIZE) $(LIBDIR) -nologo Advapi32.lib User32.lib Wsock32.lib \ + -map /NODEFAULTLIB:libc.lib $(X_LIBS) + + +####################################################################### +# Linux +#UOS = -DLINUX +#XLIBDIR = -L/usr/X11/lib + +####################################################################### +# HP/UX +#UOS = -DHPUX -D_HPUX_SOURCE -DCAST_FD_SET_INT +#UOS = -DHPUX -D_HPUX_SOURCE + +#CC = CC +a1 +#LD = CC +#CC = aCC +#LD = aCC + +#XLIBDIR = -L/usr/lib/X11R6 + +#XINCDIR = -I/usr/include/X11R5 +#XLIBDIR = -L/usr/lib/X11R5 + +#MINCDIR = -I/usr/include/Motif1.2 +#MLIBDIR = -L/usr/lib/Motif1.2 + +SINCDIR = -I/usr/include/slang + +####################################################################### +# AIX +#UOS = -DAIX -D_BSD_INCLUDES # not recently tested (it did work) + +#CC = xlC +#LD = xlC + +####################################################################### +# Irix +# missing fnmatch, but otherwise ok (tested only on 64bit) +# 6.x has fnmatch now ;-) +# uncomment below to use SGI CC compiler +#UOS = -DIRIX +#CC = CC +#LD = CC +#COPTIONS = -xc++ + +####################################################################### +# SunOS (Solaris) +#UOS = -DSUNOS +#CC = CC +#LD = CC +#XINCDIR = -I/usr/openwin/include +#XLIBDIR = -L/usr/openwin/lib + +####################################################################### +# for SCO CC +# +# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +# If you have problems with the program "cfte" +# try to compile this program without optimalization -O2 +# use just -O +# +#UOS = -DSCO +#CC = CC -b elf +#LD = $(CC) +#XLIBDIR = -L/usr/X11R6/lib +#SOCKETLIB = -lsocket +#COPTIONS = +.cpp + +####################################################################### +# NCR +#CC = cc -Hnocopyr +#LD = cc -Hnocopyr +#COPTIONS = -w3 +#UOS = -DNCR +#XINCDIR = -I../../include +#SOCKETLIB = -lsocket -lnsl -lc -lucb + +####################################################################### + +#QTDIR = /users/markom/qt +#QLIBDIR = -L$(QTDIR)/lib +#QINCDIR = -I$(QTDIR)/include +#QINCDIR = -I/usr/include/qt + +MOC = moc + +#LIBDIR = +#INCDIR = + +#OPTIMIZE = -O -g +#OPTIMIZE = -O2 +#OPTIMIZE = -O2 -s + +#UNIX +#CCFLAGS = $(OPTIMIZE) $(I18NOPTIONS) $(COPTIONS) -DUNIX $(UOS) $(INCDIR) $(XINCDIR) $(QINCDIR) $(MINCDIR) $(SINCDIR) +#LDFLAGS = $(OPTIMIZE) $(LIBDIR) $(XLIBDIR) $(QLIBDIR) $(MLIBDIR) + +include objs.inc + +#UNIX +# need -lXt below if USE_XTINIT +#XLIBS = -lX11 -Xt $(SOCKETLIB) +#VLIBS = -lgpm -lncurses +# -ltermcap outdated by ncurses +#SLIBS = -lslang +#QLIBS = -lqt +#MLIBS = -lXm -lXp -lXt -lXpm -lXext + +.cpp.$(OEXT): + $(CC) $(CCFLAGS) $(APPOPTIONS) -c $< + +.c.$(OEXT): + $(CC) $(CCFLAGS) $(APPOPTIONS) -c $< + +.cpp.moc: + $(MOC) $< -o $@ + +all: cfte$(ESUF) $(TARGETS) +# rm -f fteln -s $(PRIMARY) fte + +cfte$(ESUF): cfte.$(OEXT) s_files.$(OEXT) + $(LD) $(LDFLAGS) cfte.$(OEXT) s_files.$(OEXT) $(OUTFLAG)cfte$(ESUF) + +c_config.$(OEXT): defcfg.h + + +#defcfg.h: defcfg.cnf +# perl mkdefcfg.pl defcfg.h + +defcfg.h: defcfg.cnf bin2c$(ESUF) + bin2c$(ESUF) defcfg.cnf >defcfg.h + +bin2c$(ESUF): bin2c.cpp + $(CC) $(CCFLAGS) $(OUTEXEFLAG)bin2c$(ESUF) bin2c.cpp + +DEFAULT_FTE_CONFIG = simple.fte +#DEFAULT_FTE_CONFIG = defcfg.fte +#DEFAULT_FTE_CONFIG = defcfg2.fte +#DEFAULT_FTE_CONFIG = ../config/main.fte + +defcfg.cnf: $(DEFAULT_FTE_CONFIG) cfte$(ESUF) + cfte$(ESUF) $(DEFAULT_FTE_CONFIG) defcfg.cnf + +xfte$(ESUF): $(OBJS) $(XOBJS) + $(LD) $(LDFLAGS) $(OBJS) $(XOBJS) $(XLIBS) $(OUTFLAG)xfte$(ESUF) + +qfte$(ESUF): g_qt.moc g_qt_dlg.moc $(OBJS) $(QOBJS) + $(LD) $(LDFLAGS) $(OBJS) $(QOBJS) $(QLIBS) $(XLIBS) $(OUTFLAG)qfte$(ESUF) + +vfte$(ESUF): $(OBJS) $(VOBJS) + $(LD) $(LDFLAGS) $(OBJS) $(VOBJS) $(VLIBS) $(OUTFLAG)vfte$(ESUF) + +mfte$(ESUF): $(OBJS) $(MOBJS) + $(LD) $(LDFLAGS) $(OBJS) $(MOBJS) $(MLIBS) $(XLIBS) $(OUTFLAG)mfte$(ESUF) + +g_qt.$(OEXT): g_qt.moc + +g_qt_dlg.$(OEXT): g_qt_dlg.moc + +clean: + rm -f *.$(OEXT) $(TARGETS) defcfg.h defcfg.cnf cfte$(ESUF) fte$(ESUF) diff --git a/src/fte.cnf b/src/fte.cnf new file mode 100644 index 0000000000000000000000000000000000000000..bab8e76ce0c79500d36027d61fc6bbcddb843849 GIT binary patch literal 139621 zcmeFa`*&N%k?*@LzV!AZnKLsvnKQI4C$>D4Y}t8v6vrS5N*IF#1AvyD$kqi3kc3SV zGyv)m$LCKuf7t!){vUU(xu0)U_1+sIDTz+zWbQh{C1Llwt6$aC)m7F1&*4A)B%7{f zFI~%S?hf{QH@lr-|KR4t2?hJ3ZgJ1kN-u<8aE`8Se{+i(UXO%va{dwJ_m2~CKXKpx`|tn$@09Z2CsO{@eF4h{?jxa6-f~~mFh3DD zRm6?*KA{-_v7)E`G5hN6Ki+@z(TxZ97w+G@fB(xj-}&h6``vfn`6xRz&-~MQNbPy< zkKVp<{he#4XMKlBQ5_Bk8u5Fb;X(gk=X)~UZ@v4DKC1V*Wn4R6{r$HiZ};8%?>q;D zU!R)&K9xVd^_~OxdI90<-#@3wpJ!jaG1-gnzVpVv%+ zov|t)``gO?wp@b#zE6ewc>%F@O65#3f;X-+&Jze{Co1Q42HcFO9@^%~tw7&tV13W$VMi{^2-fd5Na>_IiLa zIB?i*rDA5XdaczCIHD=3{c~B-9P5D#QB2Q(Q&l-ImDWMKeT6;-q`=(LCn@*sRCk_XYMAP*wtBzYiuh#Depl34gBkGsnU$bx2! zl=B`JHO#m#;wCAE=g z-k$IU-A0&FPEu+?n<|1Lo9w{Hn)$aoo&DcMRn(|IwynL+xc7KI@ZH{w3TYRmJk_%H=WSZH z+*m3|Yf92yt$v=)R$F%_df7uJ`dIx)9<6M8RVWCbb;@)m^ny<-t>}NPh)78#{M(Cq z0@eg#Eu-u2-}nv~fbom!I=`*8Wt|AVYSo)-Hy~4RD@kWK?r-hc(V{mV_l8O{I_Q4S z=#eHrH2_Ks+6hDGKv22TfD^xJ9c_NiF8Psl#kp*0q9f#==mza>ly8Vadz1NuRA}n5 z`(7>@PD*t$aaE5KK=^*?K7f!fx=$z#Uv#w41irx1--;{%hfihQfqwhjitLPR6YC$? zroTO~{qmsqNO2+)pk6vhV=~NSTb&UbAYa>6XR_X&``Mo}mIy9f zWbJRsHSCR#JjbZNb0A`6E*tg#)Em%KxS-cO-Do^K+Oj%EkNVb>^T4v*Ioc!ee0DhO zKV)UeIev23BSy}L{o(jXHD1Wz0F3(wN2Iur4Gw$5&RE@kf%9s;egd??Yxjd z+8k=FD*Wgm!FG{~24kk30G*|`p+Pkp4?6q3(P0O|h0voB=O*RrJwBwBeFJd+Xxy>x zn#ms6_|Ik!+%cCu*zOG9|D^zaP;wT%^xPlu@SMT}z%nJQ12^O5b@`^{o64@=3_M(0uK%Y- zKUzq>d`in>nw81a1g8WpNjS!F$4urp1w`>&{7^;)#nMiTrdY-k>$J2uivrmH01^w_A*>*J>v&67Rh zR1)j-NZjaX)15O}-;RpK263Lrx3zbqLZ_9^(B;G4!Fa!OsCqh^>|75OYNfIvsK8y2 zSYY|x2jgMqfc;CMf*?7C{@J=K~ zl#dx!MoP~@JSQNNscinu9G8GkG+%{QegO|oy)7E)NQ_u@As_E~9KGl!oT+cVH-Zv^ zu+r^JOrE){Ra;%JzsUS~aq_1`@Ra7rEMsQ-Q6f^NGb3q=Egr&W(+CcT7$<}d2DUdc z(j1W)wF^qYxN4)H1}`ykGugqBb}**ImQxwCL>QF>UNJ^ViWD_-kxf_0jBL3;f-cV!>_z~}1Q&28bxt}VWt>T$}_sFST;_eh+tL^~2iX-^R@M-W4_)W{;1l=cDA z(SOrWFJzw0hMm3~BC;S9RiMHS9MnevD#W1Le?Hsm@3X?`TaEUXaVm0}aaJ_r*x=tA z3|QUMq%qz6iPJbl-#6PyMpsXAgB?0z;M&%b7lr!ManVw_;nLb4_JSAuh&IpPEtOXQ6 zmQ*Aa6%DwrqN8cgD%u))a?uo!iY7q;TPaXY_%3fyv}^JM2O{s42LdX3Roz*X`3Z%l zZh_l7(Z^5K*R|uSVZo=7dN2zr%PkORWqHxbhjbDKZ-RiMPc%3ulMkgrUw{Tx*HO+j zKER(!<@?e<8ISzCgf@VPbA_*5E?ku94bP|3zVter77`=+Jn)j;VPPWLWjPR-EP;~^(x)x-{*m@Ssf*6WitgfC3NOfgoIYURaspZoUfb>PAXN- zGXbih&oiB&LofS!Z?&6^wL60K)w98R0az{XnV`KWXp3wCZ|O4pR3sl0;Im3oz`k}i zV3`19JQJjv04dKICP1M2x@|^3awt!xck65;-GXdhw$0(k&&sjPK2XkKOX2UHnS)7R z%CS*b-~G3<^&MDqqkg8Y6V{9@(Q{`Y%^L>e-=7)A#@S(vEN6$2+Y$QlAI=Qp^4VdG zEN6#t(bma7K5KR?vLZ^eVO^iLNUV7lJ6z-%@q0UA1=q)7gLm{dwLq!6o!p$`+uN&|j&uYO98p|HrA_ zdnLO~n)z09>9=pZVPHggrQ^TKyX2U@vQ}BO?*Herwe)g!yE3o5r`H0~{ulzCH8II# zh-F`bhm)mE`Mexl3fVL{{|Bu?*t}JpNLR()yTU#L< zEbEyjFw_2Kkt^m~i4Sz@_I<@C;ZkM2U2E78@c2eF+rvC;(7wKU>CI~$}-w3Pcy;|_YgIgv4-evug(P&>?3BOrf%W~fu{GebR* z@x`G&nz6oq@oU|<&<{~RZ6@3tgdAH4S56B4#nrzqKS&ueZvW`Mr{vgxh1&z&1scm+ zS97&iZEYDzNG=>#tL=)u_1fB}`Yu*lRo(BkmYTKowsN)FUx0iS#l3@W`QU!*_m=&B zV80*Q?=S2Zp{S`0GMrxsU7%a8HNB>_4Fz&;;1~K*ztq4l(4FJ{g0v!^B&l6*EPeX> zjRxEWz^yDVH><6dm-U&T3z~+!P;`K{(rB()3vHuNbE+!_e6x1vE)E1g8 z{6r|&;02Lm_-(X#@urR$fN->o|-;#f|LjIYo(yUU% zY*t%a-yoKXtM%%Vxf;IVP`)HnJ>mJRv9?sNEitI)k;RP^w1G1Dy=%WTGG;1?5Ls=1 zu}(|SZrE5Pt7@|aAjs27kUOnq(Y=V9XfCQDOSbKisZy`qp-)*czT2<{8d0cLHK~JQr?Y0&2B=vjhbDNXNpQ%@>TBIF%kbAXs1t{;j@j&9 zZCPD+K~wU+iqH*S>rFW}KpH_j4*4L{s z!)*RtuzBb!P;;`*lvmHx$xVMU?HklV;2aaazN|7hrKo6wvevSxay6@0TI~m`jpf=( zO=&K9z-O#_0KLeB`n+CUyWRX#6xV!<(B`%Zo$Ht^T zE|U{^0KzBGkR4RV>n;J1=x~oT403qxdM{W5uW{ zf#D?>K0cS()w*Ci7V}12noG`{$jOiDWEK>c<_m%(U=(o2API>7wGq-iz=CWAr3h|;!0!ZcW3agp#?^DOEd z$Ehwi|7oWz-O`)P;L9#E*!rFBw|{r4++bwqg8faeSIx(FZNjHcVHw=N{l~kzU*7ND z|M-;K`q^yWW>>nepGMfkz&x7E>dUP=tCJ$5;Na6GwPH&TA$A*wzuK0LgwJ5h<)4t3 zaY=pQld>m5nKDD%&J>DwC)X(t^kjnh;iOTC!&sYZ%{%V zQ_!g8fvs@`BbeiI56FN;H|6IbK z^huI&Mig!9VZZmtl`0GsqPKzwCwd&9MR!{;(#8az&$hsfA!phvxwm$Pox@#;cOr~h zcuMloTVuy~`kJN+RpjpJtlI_g8Cpgt%rGRjD}?5H_C>d*zq2JV>6vUBtrj84ZA3f~ znAK-0+qE;*F4z}0sFz>xF28oB+T~0&o$Vfyh!X89FR9JTS6;H2m#@6!H!oj#DagEh z<)uXPM#-j)P04%}`|F71EAMZ@%NP7>p!Tiu-M*y3k?wT|Sbb|B^vrkkgm$rSphh$j z<<|=rDhf72QG#*Q_dMX=|G~edVOYU{ZPH5wu zyU%Bj+zf&R=We7>_pSeX_C;9L_OqToY?I?%gS*?+mq@DT*W7!3x%bG7l(A>hXBI)= z;XV!;hfA%P%A``oujLzgT77`oHHk_WZPc+GOvn>Uue!SQuj=rOV}KHY2JRH=4oauQe~0JiMR_Q(>j}`H(2Ov z81Y88B+bH$kWYsQ*xTBGY(r5EIOed#GBoM)ylW97x3S5afaVuU`1Byy#}wXJh16}0 z^d4exDOM_Vv&f!zdyh{fs^V-RfmMhR!_eol8`{5wpGACmjA8O~*++^IwO_=<(WZPD zQ!&L3NEwNWo0O-HjWSLd^Q5Cxt7t-Goa`xoiVqM|$qu4zC_2+Y6aevJ|Zqyos-%v$CPx%<^=6Lc(B@9ZnPde&{BBtV682ev@RR1TXJ4e z3gCrFW{Iwbf2CHhDu5P2PMDpC%h?U-@cJrK**8W{_BRKn^@`^ZHHrQJQzR6B0~Bh; zO6IZ~D5gs7Vm7<6Yi31=9f4JaB#7PI8_34Vh3v+`U~9K0H)R#7t#}6LzW7P$3ZQwgsY|2E_p`AMMJ9jxpPW zQy9WGiLLS2HU~c^vg7zM&kBJ+*xF^2VXx+U!yMjLwh0|CLCALAQ|Z`?`X+K6c7%Sl zKbm5Sv|*C96qH5O6xSJ1n&E!HJ2ZGlJwvVZhheLv zH5yAz1;@8XjuqePxM~wYGGwLZzr|_Nj>B`=TaShuKrOIyD5UxE_<`I z_<x2{beB32b(s&wl&vzkc+|>(`%qpu1Ya2RA-?OXx`J zG{7p*R#b1Wl7M7^Tu3Y+^hc%yCB8!EBluR4Bz&r+jE!E;p7;v22Ggs#QXtbrcBnK^ zP{^h~j$$>N33CLBaJ%=d2B^P%kQ^3+viWvOAVt^XSH;#lVWVt^rDlZBlL;AD7sCfS|od_FNv5OX`2HV zvTJXCa{c!2-Zkx|;GE4<4ucV>?W;e2sZtXk&G)I8KyNE14zJ~06Wc@q66M+?( z@o68Y$)G*`#gt=R2sV7L`=YX}Q`x)5>ks@GQC0^GZo5c`W%82evMPk-3*4)MidCmd zCuez-twNubEb37OrzWFSSm{}xA5{O0Zkho6qRK=m|@V zaEyj zEM{GfX4HI^LkzrljrhWZj`|B18w(s1W)GWO}k|~PT{T2otuWLgK z=l!?uzk{Z!o2Mu(3g(HO^bC|@(r60cyT*sLAHFx-r$Hy~)J=`catsb)YWIZ?d6QG@ zhgxZh3HKYvLTOUT1jzsntug^DGAihnmf*&Rb7*yBuj~P+uxSL%SGxpjdQ0PQk&;He zeXJ(ofvIZ@Hr0zE2D3K6nmM*PpK!Q$sBJ2H`?_|S z*oA^8Wl`riXBGR;2Vma$nr8 z0O?B&y8cdSTU1M^HB!VUn)kiZ$xUad{m0TNkdxapED%sY^un_Wc($E^bcUILAoZ;v z03AKU&VcP+6Gt0>iUCm17p*Fv7%s}rKxJX2v#?!C@l>r86vL%)I=P_fXB#Y_h?ucL zS49zc)a`-8f~UasT|%W#ZxT)j5PKRSkY@!|N8y3SZH|@76PL0;^3nT|_RWd7YZJaV z+^2y~+X1vX%LkuXEWlvaJM!2*^$(c2DQq76xiE#Goe;L*dbK&ZV?@wN1d7eqoCqnI zr=b}^S_GY{)_|enA~050kTN!#bK+%^K#_sZBA*O=;tTpV?JVaqcoI|DxBkm@3~swe zV5>QY&24^QHzC{rHuLQwEFa}$06S0E*^B)`7h7g3=e&4iy^gL8(%v!$isnv%a*>gs zPEft9=}e$_Zoq;%F>^1($pBB;lun21659&7GdQ@V(l=q*3or6@qfcyyUJrbI7=zB& z57wY~gtlSG0bfo9;4tnP-$!-}w6#l%$&9f)L8!YDEb2Wif-;>zK?Px03yba(NW1Np>{D!PWx*2D6Z+O=h)7D7wtXNMx|Xe zQGA#Hq{_6flJK!LVSDRfOiJCj!h<#LB{mYpcGcCZZh_fsu_CSeNQLe6#*mN~^xYfS zJ<4Ud4}01h#f3a?-kl+(yYo;tJ)UUT=lV$uRLg((h#cAj$-fi1ugbGK7>zfdcyU)0 zaL~*BFI(|gC>*2|QPz=PwOLs^a$8Z{cs@)COJ#SuT?VWu+x@SW%RbuQ)I2Dal57!D z#o;64S6kIPaAz6AO9^uGS)%~kJkfYyE>a3G^T~o!Q6BERJlyJuC=Xvzp0cP9qCC8% z@<63Ie7N)SaF@!%SCpqLrSkCRpqvuH>@{m#_uunFvPUA-5)9d zOS8R$9g&skmYfh-x@74&z3MT8)WBq_RI%J12!&n5`G_I2Do7EdmtRHb3Roysb&YyG5C-PP_(uBD zNwT*eT?@r)T`O5SP@U&=l&pzuxC85Un&Sy!T#`4RcKLae%6Icpcf3@p-`)4lVQua1 z$JK@0M`ImJ)b-de)jSyO^)yK-h8e9cpdND_cGRP^$mT5ZGIL6Akj3wjsihdF(YJ0( zc9h1(rx%IGM>1nZ{v%m^v%YyETO6@Tm@j5zBNuH!XHl%+MC#NYtSt?#ua3KKvF3Cg?TsFe3 z)|O1gU6d`>vFzkAI)PBVaY&3OuCyAxE)r!v^dL^X?+kzRi%r@xY2 zpI;F<6YZmO4LQF;QDD^(^qrFR?zbzvnrB0`R+Q(ZQvXPn&mD^qvY(Vxnpq5f}?7 zJ`t#E(U_Vs;YbYs@I#t) z?=E6K|B0IQa+-H5@CGE+Lc?yH+OSI+FXmhIGZf2;3G~;Qag(K-jB{g|)V2lZ%~RpL znAKKTChfb`wX=XZlU3_zn-&fG>#mH;-q-#zlN#{esSU`rDNlpt1R~^ec8~TRZ}wy( zPRRJ0wt{{z)nUw^aRc~2t=@}SgNfC=S9``(`Rn&G`^WQyRoBOD zRx}w1X;#s*Il6Ex8sMR_UN<#I{8aJBcLL*y>x+ugqO?7r!dZ{Am z=pqxm=aD6}ccsp(42Zj}S(&J6Yf_N0(rkJ)i?y{%lSpaDyHfQcJ`{N?0zf+Jbnaa# z`AXZ@dhtTGOy9I?SgHZ4<=UNE+mabBq%y1GGM_uOwJLojC1M_PoJ-CU+yN9A!Z}2Kb8-;Zl43I8yXj0E*jm3X6rS<8o zf#eS}4nrx_(V$~B{KZOFpmsefWAfQps2i99-rXu(Ihs|Js9l*^n-veKEm>oDE)N}Y zG@zMkngi8O?Q4q3%mo+NqR~KHt*j=+_tqC{?aJpijlQr!u`P{iG+gM3WAYA|+pLn= z%qS*vFfFX7m_>YZz45Rga6x7SY86?qp)Y7tOV(ikO52B$8;xQCHBBJ`nld=x^HH+U zjCy5p(X`c>i@efBIVGD2v4$6`RiHx;z1C)ERSqtnGdMn%i|Kuf))n>>+@;laQPXto z4vi!o!OU6SsHGyg8nQUR1jcEVo3ei7YOMK6v0RPy8kR*g|IzhtTUm&m+yWYXsM;of z#k(6sV@QHUz}#287$KkUa%J7Gth*( z*Q;cdiahhu@KKopdA;p2N&zW+bmbKSx(Z+3o^w1!8$e5pM1$q0si~2tqd{73z+fsY+R>^9MsGI(SB;}VwH4aUOtvArXy33ba>+cYbI+U4x`*kVj2L`Qu}HJg zai8B>^p6es=S&!8KmXu}`9}FPN9;!~wz#yqjDU=ioUQ;FMZk%Q8)RJ}p3M0wlDyP_U(}{*=tc|vTM_`; zqbl08o<|Azu0NNd{@&2adhY(udTWRPDC}}PlOi||MX>Z~MU&%X;^2}f1<-EW@Xe{D z!ZQeiGC|;U0K=0A0MM*R5A1wsp_p9~%&{=n>7hz{2`nuXx5kbjJ0)k{#W8I1IVMh) z>FLRB9BP7U36n#V&5Q5omoyml>MFY)#a@OWgJ@DYAS>HNpSdYh%F~;2X(MKTZh+h16BsHxaZ~oGVS6#=YZ?uxTHC@GzmN%- zMB*_gnvGV=%+g58v;yVE+-P7;$0qVhy`c>WjV#R?EeX+fJYU-=@`;}EoEm_%hh4;- z6E|1z2$e6%t_p2?x$w7qFDO!o4lSohM6igmpng^3Mw^E)S;bIl)#jp+sRAoJY<$d* zAjS@e<=DJ&(u@%&4>7)1YrY(XCq{ zzLM^|pL&`o-c$spCw7UZGEI+7FMLrMypGPnR=f|H9-HHVCA|j5lapgr;jd<;L@CU#V~&s6HyYs5if}~>L%5$IP+&Y{fRuJag=)RiR$uK^0=9drz(rLH}eNJ z<6X_Uj0d3XfpH2x;zmvV83I2@yGS%r3mSnEed6(~^x9?lE|4dv^zh^;P3tr>pC)WB zJ7J?~d#Wx*SJf7E9*ycXt7D&hWM5Ac*ud7maeO%kbDl_WK_aEq>Vol()a|X;t1OMJ zBi$>F#!vJ>DgsOqAc>jej@iNNM;|>>UNsNTF(O@KV#QZ&-IY@4CfnXbKW>-jBJvts z(|h#OGR%^%&^0`AR=b@;Q_hwoLOfc=#XeW?$#>O!r2xUm8)PzTA-N#Zmi*uxQ+n(_ z&d}&Eg9L+ZCbL9ySg}`4>SVBu%?h3+Bj8E|SW5hEh{5grB%42@EyF>;JB1X2{UY+= zc7b%Kf56HEW|{v9Qvg?3HiNP3J|xosqkYq2y@XiY5N8TT7(?p+&@H(`7R9uZcaQva zv%4GeO9F1w4GV!#Ou;jkx1L7q1Av4ecY5ZO9GKUyk~|xIO;?+=^i1aBIwxLGtKZ z%2VIAnY=*$*?&j z+YEYV@9{XI@C*)G!(=4od~BevVwv#B3mEv4PGxE{Kr)WZ|~&UlQzk;N{|gagJMLh>On-1 zlgoL(gj~1;VPQ9fED7kJOBN=syJNQmf0IM#E*(#OiSe!iV&(y^(p* zBOPq*Gh?v5wUXIm8yk&_DgMyD&_=yS;UamsFqC4lz#$UMM>|7^=jsVs(2c|z_aUbg z&J&yJ0OZ%$sMsNgTPDf|{vJqHP{?&hpPenJUPLDG@M~o6x)EJgj%Ac26)Cq|rn)P{ zLH`fHcF0Ng{UdQn=>!=}k%3)BAdt^1^rRTr5em^WnPzH7vXvl}5Vd1V>j>g2NG~Hn z*Fnb32nR=J;gM4zQJmqUD9Mhc4Z04Co3gplSL!)Xy7mr&haiE%I2{AxL8<_!C0H8C2k66k~@vcA< zL29Cv(z3!&a}a7208xP@Wz*6KZ}OC{R??Nct!_Gq5tl3@AFX2~ED!fo2atbj5$5oy z4!F;jovEua8dldP7SXH@$y+iql4T}><5jQgMBSbV2G1gZY(--kDH@`eeZ2*^V#L^7 zt#O=k_13R9Cplk%Fx*LFB2IT4My49hT)tHvZ=$7-o&KpUYh5Z>lLb0eXOZ!@q?Y?I+%PFXbf6#6OEy{dP03LdQ3x{cczHepMn_vV3H6O| zCX(t=iAJ}6>oqABatdEj*8vEHY4J!;j)QQi(zPXBu|nq|rnap%o+@@t%8_utkl?-w z1b<@z$VL?WIuuQ*Z36LBjq%`-$rPJ;n?qL;mG+G+?ob=Y8cLw6Fp8%Bv!%{?03r%p zE7NZmvwGn%MHF&E-BEri)zz#%8F0youPB5oBavd^Up7M4O@ zDJSv8`szd?57Q16E!O@KPVA;J2XfDH;kiuuQruimGgPY;r32F(<8avbSdlywb&1CVlJ}%^dFj4OvvLzTAXdPTM{T!?t`k~Y^+H>}~Uc&k8>%pcgJ0+EO zH^YE+M=&It+cuph%S^_h#iG-;6a;CQoDU1UM|yEodIn{a8niEfx-qL@pjx5mOquBx6u{qRZLg9#lGK7CVu! zn*2=6;2*&r);c+MJa)ze=|tkd31e4cjE9_&*;?S6=_n22l6?X2FT0iWa?H-9<b2OxdO2YbByD= zygcOTM6gc8o2-TI$OsXY{pwReDw#zL*{hMK)9j20!zLe6@meMq z1TS51W>WE$@uFtPa?XfFEGvQ@GHcbe&o+QP47 zOQM{lNMHo!rECeJe^hnjWeCE^SFw4IaQ#yI82N*WBS^U$Jf|q;Sx(K4wc#{=q>WDcYO5Nga zstmD(nF&SByMRuC>>@I8n7#DhQfOn(Iw>ENt9eAQV{>TNhrK=29ipxr+U8*MXf)3A z=gE~$su9i-%R8cFVEMTGB-K>}Y7TmL z>uXs}o6lq*H&LeI3MtEw*jmv9%02fml2R&h6@DcPa}oRjrNq5;uh$*5d!Hi=zpoAD zYUYX82IGy9ZaJ@Hv6f?TUQT{ro-ZeFzCi!(sgSfpe?<6b6ri*RIiwSzIo_b$;b043 zbJ)p09B5xJ4PW-sPfiHUyA;?x%ShcQgqHlJdYU?U410OVPhe7%LnbQV?Qm5>d#U*x>f6vP>=_ou#C0UWruyN*${+iY^HFzoxT z&W(}Z6hV;mH{m23gO}F5HsKGB9?Tu>D0WWIK_rMUJKsBV_Nr3J3A@IK#bW_51Rp_TI_S#pV8zFQ2n%{4U zuIRjK_j*2px|0SZOOBCPI|FQuoH`U!@=%a)nm(wA|3eaG5h&5d9 z=ma8Uk@JmTVQcqoE$?mU>w|8p0s5QC@kG@^?mRwZ|8=9bCwUPMkR5BW{;y(PNE=^X z>ahU3;9+xz-`(dZW(ejYj5QR_{d{uCJ#k1u9AJO!ttMiBoKIO@N~*uo=1eSpuU+R8 z`O@T}eEEF$Ep9Wpm;$>Mey2+d|CmK5x`>-7qw}`8x!bb4!ysz6k47Upo#Kx~8yowr zZ1o)b=ipI|3&dF*X9{EI7ckh*4Zv7@ZxQf)Y;@QX=%Y9ZgHODqlGWDB&}??GF*p!m zfvqM@4i`cpnO3ZGpWxhsdbkFHXXw-1Zx7O;zXvIo9~RW-oUbfB&NTNF?A;@V61~7j z2KPCK8k^nHi=?;f4#@k#BZu7_exSI*>Fyg;XUT7iLAPA;>s&xPJ-X;3zhVz1e|cmq z9oB%V5-2chnei6!O-v4X#=Bv@#14~Y9!2RfU=fx~hG_dSk0x@U&7YaQt<3~wV0WL*%(HM1QeH5WCq91VAS zdaVF)-zK<{HiN{ z85trV>IUYQ9d$UDrp*#(T9q6Q4fzwqan9~eUzSt!#a23%z%&payUYBvr3~B8{Ep2o zhc9L<9JAi`#N9mXnBJc5s}!{ltE5=AaLyzuFd-bEFyX+sRk!t_%OTcgT#EX##r(#e z*!~3W=kuJpoGu~O%mpDIV!Thsd>o^<^0Ybz%BSvjQyM;Rbr9E{&?*G$jGy#EwqdxKri8|so z-QEx53X?Cyr7@;xna=72=Iam+nZFc*DG#%wGm|~0UWw>o<4u1Elj#o|Z;~4eA0Lx2 zdo{anEUfQRHQy^?Nv)QICZ={SyI(RBH}54`%vAQBWl}Xo=_aujM&m@9&FzzWJ^=IIP{Ue|*vD*;ZX06bo;h*Ce{OT8vvH(`+PyE4F$xb$Ik zO7B-ty1=6#eF~7G*#sF!tuRHAkB-o6Es9LGNd!3dZYrf zBjgoZs}r)xbI+27RN2r=Cz|v%bCkJ_ycgFHRd-WnW!~&VTLv9Bo*etL-HF)?ZwjFbfaEQ=@TZq`iF59m@EaM4_ceyoFyCNe> z3}k(vj`hJD7uk;dvuPi@KL-?lHp#A)k%dTK3r0W#)T69hy1~;Gu9e3YD_^k4`HT!~ zIk=PKvKa?;_)R5+9w^?vMBCROu!~^b>QT0AQXT%us@gNqw`AB0m}OZ`uNfHXf|?bH z9G$5yCrM9R^b{;o`-Kq2ZQaz{w4nI4h)s{sqfVUM{MRD3Jfdqs@oN!!+X`t+n5D>w z8>=5tORH8s3Snm<-hL&jjYOyYZrksU{cc+4_4FaBd-S1$+{4G`hpEnTKgw3AIygRh z*SP5~yil>z+1DD4sqAZTF&?30Jl1(%AMn9rxxW^V0*|q6zxLbUuQ5~Oxd@#hv(l&# zYv$KBE?;kYKAUo1ckn2ozDj7a8($wNjl4F_UqgP&W1`tibE#63$?protSuXNk}4lb zbOYKiBokQxGK0kq5;oCXWS*n62XK=FiRc|9v&LkF1Hw&^W=4?V`SVnMJ)`>-Z9^n2 zo~-~~mn~>RVj{|~8w}>xdi@u>H~t#G{mOAUqAA-`rMQ!7*}oZD_Wpj$O-;Y1K(9VCg!F&qr~N<@#{ z*_95Roc9LI6YFxYx&FYO`UC3+Zl5P00wKr39rS-a zzD2i}>My=U+f2;OFWAuKY6z2?@}!B|coQqO;ZSXer!3OOE5z#esnYiOkF~5%hclA; zW03X7NUG!Tl~?5ijYpC+^uGA4i9yAN=4~uKYwo$sUcwO>rAjnb8g@+P^ruiLEL$oBns60ZcL+*#_6GEVRFp^*^rGDbf^h`6ajec>XB!67B15Ow0*vIj{oF;paP zXoTo1J?TIo$p!}^j$Ox)j)iI~>l9j%+f5Xu01Kx|@Pgh%MmGMHr?~s!fr=M1CAAK;<_3D-jrWV|XgKr_WY~tdC90zt} z77=e3)EWg_jS3m}OyU|KaH^3LPmP!dot%-*D^!x}g;9bFN`hp!by%i==vrytsTG_Q zOvp&p(YMOa=KGL>APwB1`|kvWQh;E#PCKX_O`xqlfFEj|q1h z=%YE;RrfDQ5xGddqdL8dtur!65bg-Gf;8~0?G;Q!o9)VuuiZ%@c!{tv7hw#j+;)2l zE}r3q(IHub>A~%T9miZl6eHZuS3UGw84X=&Me2%z6PfBFIMyZ1ID|6vl!&gwmNo?4L+shrOS*?}@*0^r3-5IwFqa?r zBt&K|1q#Rrm8jsiN50-c`@QjlVm^prU_x2aY|?AnaDy~$T623E)y>9KHB!%8f+N) za?4z>C9}0ea(hq-4!eu>sgIHY?J$-trAB{&RZ8%Nisc9t<^rkES}$^Tn0UlTv=QV} zknJLJIknqss&W@GN=Hoj)ILe-+ett15Bx~+-1GdU>_L9o6zDI042YDa3<6a!K7F)^ z2C6m3=vZqMWt`y{pgO2ZmGLPRPzovPiPX_~FZ6KFB!{3(>tjW8;Wx({p*nOx=t60i zDA}i}?Vmc=edW*a)_?P!IPAY!*YEoJ_owpMi{c=kqb=%kd^WbFI{u2!;9#Qs^{2T3 z7(=U9nzG(jeijY(ISO}&K2OyR|3P*eVH_g3sYfb;dk$?X`B-7*xSB*4-{@jTWlk=} z;tX2PX|h~FH_=%H_@gyAFk}E0Et6Og1hwNbf(fh9&yq6}lPH9U?RjlID>mVPim*SX8o?BkDp^; z`am)a>J9pzekYF)o86&E<~+d@?WWp*Ck3#BVm&AM7z_?fWu|rTXt2f6ZPg zd@+NPLoZt-%7rh2e|C%iVd4C>MqH;Uef==S_72gil5~LD;z&%^3mF&P;f7`^Qfwt> znp(7&f8f>}1(on#*&NbR{oaH*q?BH~2e1?SMIg_=7?r93p=8Q?>7OQ_umq>)gdy)h z2=pWD$u6#~OrXwZ-gnx5m9tO7!b?0%I>}5mg2CCYRCF5k5$(0aldrf>(h%jR@#e`y zk6CpWvm1Z@?)%^V@yoaEF+TMoQ73Ncs!F>dpr{oj6Zog?$mI&@P9;xUI$5FsRTSkw z0o}LBkb3m#nGiOF)ZL}25UI~N58iZuV$NJEd>Yd8x?8WUtu$VIR80B=900qdc-N#Y3f= z&g%Zz(X_7Ty=9~~Soqe)3ueg}Kr4O^}6UC(Y=H=ONMNCvN z?=dlS-+gcF=TbqG5h>*e(6kzgh)+Di#6j-zg&2&&l96rT z;_y5+^9~4?hmoTo4&Zj1v^3^CnA%iv?F#5j8-V;JXIjB9)=GNd$5+GH2EGH zX^E_I3$yx^RFdICXr|uIK+G{JK%L=W?2NJy8doHNwI3Ngf^kJYJM(N1RdhPY)R`=d;m$ojv1P=`}#_%4f)gBU2vsph9HLY&XD+ zQ>o~y8ZR{M$Bao{JrdWhk;t5Y?%j?t*7d!c4v}kjyw8TOyZyw1LqeLdC2j}#RY0F0 znVot}R3uSoLk7nncTyOkl#x5;jBBQ1AzKg})AC2z6$a^RAowLCfnH; z;)({*#5_^23_OCVHdIwpm%ujEuqnvTCGPfqG8s@Q0Q#CpL!ncV1raZYC#E)`4oPwP zt%fGX)sm04Niw^L<{)BWKYl7K$Da@L7KN=NSV!KrZka67w(-1ep@=W-3EEH2vR@R; z743?r7D=+GWD>FyYfjhQzM1ixZ+69=miDRKgxa}`V^KO=rW2)3-FC!0m)*5k*0sKm zSsnVq7vw9ED)V9kj^Vy997)lcs>kB0`|( zs7M_Jd>@CAocw#51oao|6n&atMnOA5kzRA~)am%%aGwAWwMr<=f%#+dlUT)Xt$y&U z_kJkx`M0`0J(qE@h@78^=;;&)KS%d81Tn1q;QnlFBssWl z`QyZ!%otKoC{erav9fL3BFuTmo8mspM;w_CRIt2=-pTtXuZLfJk6l!guX}|{;59wA z_k_t5iA{KKbKi3sXBwjm28`WPZL+(09eBxg=y5bv70Rdj@t(_Q9zux*b%;=6aZ&Mh zkEIXAvv~HDhLqM_>J1lVB!NpYN*@rs!Bug1RD+sY* z4^1MpqAVdWCDh0@xAtKlv07g`{fZ_pr^0>Ok0;iwXZEtRrD-*^_dz=& z=o9>li4~Qwb?60YBZQ3Hk{;ir1_b!Wk_=r{VTj2Y`WIYlSk*`rfZL+VAVs=fWY;Y& zc1`MiDr*`lYZ@wR8Y*iVDr*`lYZ@wR8Y*iVDyvn6%Jd4&RJLw;*Dde5MIWifvi!RMw&lUVn(R?Yk6)INn`Di|xAm>i9^r+E^BDZr{oi8`f;s z`S3!>Qf2+t-P~0#qj;VZTeYHEt5$Gp)p9oVa1*sHf|z+|RUaOpsOh(9zg03#WmRih z)tXkdZmC+gRIOX8)-6@*mK96CV(C{b{febuvGgmJe#O$SSo&(k%5SOqYTH1oe(s;P z!CU>@N^DaW9dHXJCBdr-_-MG~vy^QOAx}~WSUz4@O%0IGlL#a|2j}1BQvFl!dwqGD z?DOgx2~@D9Te_)gc|&UbW>a0vh`x7&g6vBz_D$hF;_uy{p%zY4?Mq|rOLO_YANk+E z;rZXc;rZXc;rZW>{O{lJ{O{lJ{O{lJ{I??it;l~X^52U5w<7(ZTaS@7pMDk?#n>7e^eO%)D`Z6M*Z%mUz3 z{Wtrp-xFYkg35oXru>&`3IqczK!jB)3oD(4?cq}WQz??fM>GhG#9UZN z+CMC+y__a_nu3aZxXv%$Kb>?+nU4`ZMjpmv9>I}O5b1uxCkRV?KUC($u5I7o+V+uN z^!Vud&;I9^dfVgv$laej=Yxm3?SSt?jf8AK{PIJc!NkE%ezV=;oQfnKv(@Q{slw^7 zgXKRJfg=LCxg*8s3kenB-ITJMvZfr}!Vy`!ku|)SY8F=&-tTC^j1>uAf-FOfulMcm z6u`l?vxf`3`Rzmhn)s+>Y{Yj>vNqg7>G+`+U6Qm6ncaa76l z;KU4vITt=ovJ1|wKyI|tR{|N=l%S7e&r^IJmu3^fNq`VkH$(SljF96niqS|@ZS zyMEZ`dx5WJL1d2Cn+TOfh+dZz$lN`+!xNLxcXH~rNt_pwlkFC3UPz;jMhk4&a2WS( z0Fsix0=FZF%Gx0oF;nYS>jX@O$!gca$Gg4942?xF`0B&32pxJFFC*NBRU}y*Sx{5d zrXobr@KgpdctYqc)r@rYf?*bSnrgZ1a*r3pjr73B;XE44IErBq-n(M0=BS8+Q=jA@ z4p~HX2lw>q3R{a7i~a`uB1TDNyvo_@XyHg^?tI(~g>4O==t}nQlW^1mA_RjYZ@F*KArTn6ee`BfR%Zv zbemGcA?9BINY+&!E}(kwjqKQPjXKy~u+9c8As?~%wVEs!oxsg0y+mT64Gdw)W7m9n zlrO7D=W^FVTHbZI%o>;FRcpfhIi|n+L-ib&A=byJKpb%C>PJ_E%f1l|NSCQv9H`lN z2y25}gpAF|Kjnu-Tofcgbm#e9@atEeA=z3`av7-SB?+gv`H&2|T6`Z-wz+KOnQOun}wiaSg z*%+{`tQoD1;eehc=Qq74MNa8Wbh-;8_?%cTAF%8kM$!RNk&YvckBIDHeWS^*L1jbf z9NJbY%UHi)9-H0^=C1Haa8J`gZY;i-xEwK3y|UIq#(!fgj8eYwTG@EmPHi7M=u35n zd+UV78QKHwedkRd!ZN$7p^@D&X16gPsWW^@j448$-py)o`Z^o4|^mMQs04-IkdfT$ zE?~iUR~Za4OggC|vPxK1*UQ{}W3pmFQm&+6vrR+us%_cjJti*f7krx)7CGv%hf6d! zy1=&iKs-{v7~8BTv_I%FT{!U~e!16^y+5J{3uY#dAnzv%N*%>UYil3q#@GtS)}OGK z-QTkjCYRgoC&iYS`9>&gjSdZW6S(aSq#aITl=RlPw2v?rMzT2o|EF{X2 z*g$=_9`D*lO2KANYQeOp*qx=A$g@~`J~B46=J(}9_dMBm1V9;Kd;45Qg%UdGfoV!F zi6KQGLP6t&IV-J3w+bb>?JGzG#E{Ss#T=pPqh%rSg8t(Lq?iSwwZ-V@!B&Dw`07Ri@&eqXa;R|4rT^ z<;|E7v``$nufO%t?_U2{$N4Bt#T={D%BEjQ7CjUaxTk?(Rg)xQFd98rp%itQasgXfFEO}K`N4!3(7~16oUMC5iz7{dQrp) zLeFXF>9=C&lc=#D?Vo0Gxc!aM*8VjU)o=(jpW#fHg{atv9 z-R5A914`z!NLji<0tT2Pab5&xq9$!eMBNP;$!kQH9rlef2}w$+73#Sta48hCw1Y*Y zgS@Q-kub&q;4WSUi!Zsp-n{Gh@r000RN_5&KvMoge3SE+hasQ&So%h$n8N;mj(Vss zguz(VVPc`2^EhXl_F&RQg+Y9(kK40A)QbPWYNT;n&(SO{n6_ojw~dj zDIdTbTVes>byFMAL?xjg6QAVlAQs9fQH767nyJjxK zRz+!rmX%D1J5^s#cV=c3Ljcj#zy=0%skm715&IV{c(zW4pJhI+Wj>YB(=-9?1TOwI z>Xi>p=1BfEH~-0{euaj!Hgwej9BFZLwYu2Sw5cpFH>)k2ge*5bq}i(dp=u$zd?8}( z3$2q%vsuA0#jUrzi`6@|H61h-Yi%n^U&~l}l^!QnM3$?RGnFlp`vSl1s;A?L`bu-T zwpOXD7=M->ouX>3UejCj=_UKwjH}XCTaYYQmjvQ+t+j6N!V^;aOhqp@l)hST0XLU` z^;T^~>8ol0;h(9BIW7m6s_PVVFElJz1X?P_zSvP4@*jy=eATr*j{qAK||mOd4X^~TzrX4N~d-e|0QSY!QeL-%CU z*=mK0R_0x`eYde}BfRQ0+7xDCG|unorn#-7<1S{6&#KL4ZMjO_7qj(dW2w5l(XX8SXYarFjJWro5qD~bQ0A#ULfolcLfol+LY#L>5X197w$ZcQE2p$$ zw?CO0D7N+a7TCmVhj*Wr7+WCm(cc5OjhNk zs@OBGf2{2a74V#_Es@hkonzMf#{I4D_CG*iv;V=V6naqtG;`D;l!niMDi!-5OQoxN zDu!wJ)pt3uV!9Hj4pjU@wK7R=~5jq5m|yOK~hTHjm3ngm^`65xs0P9ex9n zb{N4E-HpPix$K$tzAFv7G)NM^o6cUBq@L~u`f-`++?AZ&g2Wt`dhl?>IFdYw)FI3O zox~zUD~DMb-72}wm9mAwLX@S5zhnoy2aA4QDwt7NDSyrHvJ{WRX9kusi?sV`TY;( zE!uhDtVaFm&|+r6Y0$`~!}dBSxQb4L@E3HdT*zP@gUIH7e>4Ps!#L4D$2N|u%# z#yP`RYj-#n^2VRet*w@W%`=}HoTi(#KUCVrJU|MiS*`j}axPonSgh-)PdT5#z_^-6 zwkwM|=Uw#kuBMz8!(wIW(+!U8iCJI=Us_e-t*qFI`vOPX%Cgr2N2S`nSJjzyCcD$n zsr53^ut-*Fcj9=xNOD*Nv)LV(FZ9+W60B4a6sILtF^7ETl-%Kj3Sf?)>_pjQN?*4w$I(_5@1};Q!O=&{lGcD@hQdgR;p60H*88ce}yxD?ao~a zB75COp?Fbv2HXR1-DS6fTeG7CQj7LIjN zSXP~2FbmZYi-ila`?2$D1jryDY>fr7L!kjPg!V!jrelz+L{;|Fr}(1 z)^Dx58|~%BJ!&%;+Vr|{lx9isS(Os#gvKgatSK;v48D5J$FtR@L9KRe35dk@v%#3l z;0IRM=p&%ppy_lk6I}fxW>|$zyqvYZU_e)+VPtJKoT+I{Fw`x)U#N7W$vU7?_+!q# zY*)ly<8fV&d9Z9HUm{xT)YrYZMXRinB2~MlMqGenCPW}6+(k>%Xd32vEiX<9X_j)I zhmRI>8s-t~Cuf5eg?h(cA=z4Kh9(vj&E9CXoXKbmIp$(%(8+e-Yv znQVD+348=&4?H6FBW1~|GlR1XtBkd4jdkwbWs7TpObxZcX06Iz6UD;OTOl)A(kw1x zQYvz#vQeia&nuEy!I04^vCXW^Ia1WYjGDw^vy!=0{r!fsE5QnekZC6gc`Ik$CV%^;#VwHE7_h;`w=Ir7zhulYwGXxgj^xx8$#>XTMuqp9*qx9+2Q+0r#@ zi>xlD4J=9uq6BR=mm*a{=F1JRIk_)cBEy(AZ5Sl$*`|6J4(Pgf*G%T4H=8YQtgcd? zGehT`=SSxN{f1`2tk|Pke&@vn{32N0iFMroGU9mKzUCa*U}1}wsx0>^wYG7X;bu3R z_0Mcgu2*TNuk?Gy&4j^Sp1j1fY{YH^=Lu-~*JeGtA5j%n7fs9Akp-h1ZI_xepN&BY zSm@W-(5%-rjbL0hnv95e=hY=cS=vymOEsYxb@07rt)1_WET)#`2|65&6S1GeteX?JZO0EULFXSo=|Z$m9&Dn(1$zu2sI|${kZD++cxC|>9UP*F>o;GJ z(e>;DLV*64aE+o%1zvGTDFvSSLXLw^^qQbMwM>#l5B|Ud7R2LTkgQMB;(pN&HG3K{ z?)grp#!H3$P!jwEf*T$T^NKb~K>|9EBPOVu6IMPpsGJ$xeInV*`w z#Qlr=BJPs={+&PKE>8Hw?-5ggKjOrdD14=9M4TRLE8=4CHFb%Dajm#d+&8H-qNf>% z3&QcjNSs}m{ToJe_X!uM9;WB$STx%0pG#6(+5jGyQS z_FqY408lzjUC{L{cm%0Qs+HGB6I;o#-XVaA|6zts!ms?TqQoXACEU2q`ZGGLT>Y%zAow zCr>xDUyIh}j9_$RLD`ikwSw-MBz1gCx3H>{W5oqAJJ6~~jS>+e5|KulW6PU3cBDae`RXE6hsY}JNQX&op6iW8uC5j2 z=fwOx=treXoIGl6J2lwY*VZ_6sK|7j(cLrw=k@WsX%2L{o3`7`ba3%A%5-Mu2gv-& zqLcagb+w%gAmXcQcev!FF?6$la-v^f^?xGeNf=bALY9o&Tjh)*z~Bmm%)x4PZ9|Yj zTem8A4E$B5GrbN8Y_mEpt)aO$R?`K%U-vul2-#|sn~@_Tsv!os3U1zun`sC!>kddD zt3Ygt;8fPg)+d4WgIeDkU?^;C% z3%OiOpg0i2J+P~8qZk$Jr{Mg=TR!4)VCT5Y+_;B?g(|m07?pGIH}8gZXp3`_U+Je4 zCdW`aNh*;Y1!uEXy;_BCy@V(YM}`o1;4WQ0n;;}%ud>FKFVo`?GAk-wJuhQ;*y*UleVz$!?i_fJzY=%ErsaN3NaJp+iY?}x{I$2%Je!o#`M*{12Hg^I*6IW9~d8RW0{*$jMP-w;a!{*^qhop( zv(}x}`h&&JsHc{_&uZSC&i+?XKpM86X18DO4z_d+GT-fO>WQAg*1T(4e5^dpV|h+4 z=yG;D&wqNx=r8p`KyY$tbJ^`pwEzC{f-YsZlSRqDys%fIu#a!wv_k*#5-()8-K6hd zUewj>wlt=I%|2%tJKAN29?9$9Q!{I=FmTTuzl+)Jo6l?5ivrov!#J>4MGv)@rPp|PsSHzF9+j(hWy!G@#PiV%EX~v5e z@Sg(q(*ArSd%gP*VoesbWSlNks@YFos2vx!-SG)klGCdE|El{A@VKfo?F+adY-8gB zn0hgAEs%w=>BJN@+X6K-l5LQkVKf>^V@oq)ie&-mJ)7N4wxlPUP47LMUN&|6rngOR zo4QFhJt4{ee&yVvd(M?jHv2#8hX>8Q_kF+9&-qUKz8jZfMqz3$j}CL*Jj6*v?Zkad zsn#Z=69tQHULSdx%~)(>wT4c| zBZ!+a5@zWOkp`-f)C*A3t&oQ85(2zFCU`h5 zM7(Y%590xuH%XA_4hl#;StPPB;qD47nSp@FVFGh*PBrcm=!!_C2t&7zg__w|38i%G zcBTWJ4!OYyr5*2h{6Cf!QUwz+$V|@&7U__lJpKEn(dhmjj1! z6h{s;$+MMs;4?$je#W^wg2Y_fFrVo!=r-_ec? zmYvD!Dt-=j$;B$zbHr*nwob6r&xeGtzK<8Uh=;#@I5j}%o&z{WL(##4A1-)daTdR^ zDFR&thYa-RPzP-?oa*hxi8)>=$Ip@eK2jdQ+dE>w@>|f@!r(MO3IfG`2mbO+#`tyy zM}qbs2KX`>7KC}F{$vj+!6v~l9T$v_0513LVAu+*7jr!I4jT%aPjX?+9DmuG3;ozh ziKib|nIBh^G#uf=B|rYf=bNa+sMaHn_#^p(b>`j?$rb*A?FxoTW{)7R`LG}k3n7im zJkAKcfQC~hJ;R+OjaIQ~k$!^r74Uw33hEKp3!V#pHB96(HFDsAYZtKpX>z`vT{gHw7f|1 zK*%ioWbbC@7nZHyI0pwxn3O#Kq2f5I)R3YiQuMG8xY2Gvf{ z*Mw1uQqk9BvRMs$r|@n?uHp}WS>;_E3L{Y(C6XA+OW}nP1Wrqb;K1oJ1Rh8*_YbFd zC@BE-6ZH}RnnGO+OhubzP_9FSW}qg|Eb2=lwCJ~UerovoC!W*EFPbM@I!2ttNW~>< zQtT7eB*aKbghtFw0Vi;LZbz%B;_#h|JAva!Xs$0lA|xx?$r_+fmWnWeC2cbV#1^1= zQG1gtYSZ{|3zoIzuj|l@3c(8U#S&Et3{RINo~Y4a6Y1ctvAxrW4o)1rnIKyPLNx_X zyiTo+7LUAAy$tn&p?c0jq2~*6REYRL<&=g?f1)R|z&=CXE+JJb7=e%jO>B?u9XkFo zkfq7!g&-c(;dJnH4Ajwb6QY6+@;Z!}Qk)B{rDBmMzE@MvWo?A5%0C=$(i7O^28*t(cE4wPb1x zM#4@hSvI7C<{x=jQA0G)1JUcedXI<01%8B`u?RT_U!xJSK3$${#2(?2wnWEZg;*yS zwRl!Tiuq6QkDr+8Arm&WbWSy>7Tl2<*Q~1JI zae^yH?55D74Hrid=FceFlo3CgGxCP*w!yq(u?|ahkU&K7 zrcQX+&Z0^(Uastfg+2aCj;e}WT}ou&luSLc6*O3Nq->yta7wm3RO&U<6~eIbztAou zD%&)bD7|27dN3DC&U45oV6$>0Po;*$uSGqD!7#F3RxCgw)x^k-r2b~hqT;(5OXy_b z5}8+#wX1vqu5}vZxn_O*t+8#GfRZUJc7DfiDfjcmg<2l-cJ+TktJGBS*{~^MUWJh@ zPJ$S#L=?o6FJ+Eo19>eRr=qUqtCP4~M5ZXsbA@sfS&6*WUz)>I(3B4PN_HzL$cZxk zz^h@oCgprOe%6n`$YZIFsVBbSZW0OuRxzthSQlk$HMrP>JflEMFky%&NStDi)ZTzX z5l}KpvvUnj9~;bp%fMP`Dqkzj&2Rv~;hE|q{Vhiy$lfJhP~dDMG0)|(P9MNW0dNMc z^-8E?bMShMHdCBMnLwtAX~J@^8jYpSX>NvXc*0mG^;5Lh0{QS54L0{(v};0HWla6T zC?;%jQgSB6iW=@`(GN0!EbowJ!10dyzt!xbIuGaEu_-AyyV4i0o;?{%n&!!&o9Bjn8D?1eN3c*G{Zo`j$m zXbEfR4SYtUm*uQpMbBi)Q%$DgY4#ZPP5fbYK?{)$j?OMbMoDKE*ytjo$ebb@e};Wj zSch(s%~}nK`;N&88qPQgQl?~}R1yQZv&JMRWX+;eQG<#|3z`p{ix(=W#Bhst* zw{(+KRp<*U^g8+>y$&es4~per>m7NIszvp3J%ge*Ec{G;2?wPW^w#Jz$6?bG(b^FI zFkYQlK*=w9i|!h28_hT&1lAkF4-&6xk)=z4a&k)(l4dA%l4JOm?Xl$D@q`i5Beezy;^CO&5&J78Gsv*@)-$mAtr!@0|^&Nkals1Z$n#0@?4|H=6b13l0X9bf7>5Vw2AwTG@q6iZmwSid&zIlwcXw#MI-#vh&Q&aUKoDFms-)4ohJ{f8=o^X4zSOsulifjkPb@wV-ghzEDX-57?xn z3KXdukxbYSmny)CmHtQPa0jG1ad+V<49}CD!%S)H>o#2B@JDl7AgBGkvx= zRG7%~C#rAZ>`J^XmqP_Y=`Dm(bwN8!5l(=Eg*LlpwsLxzS(D(&UZ;!4O|PLUS8_0GQ{X6tRY=P%v3NjVL!7 zJe85B2^5Y@Z0H-}FIptsAXDDblo$rLWwMHQrm7(-_sk&dDX}1-jxGo)70MXo2Ch+y zsxsSu;CZn8qUk%N!XkId4mX?fF3+hR4O`XdS?20caHmP>VmkCi{ly+7SP*P)qxkqU zHxqfu-}$96p54Hl+W;Hn51hkmRA;L5RQ~$Zgx?1|Az5%xYT!H$K^R-zrg=hrfz~JT z1yr3PrsDZpb)LucqycU2nLtxh+Ug<%b}%q4g`z->QF_J|aK7E7;>QcN9S)1xx*!9y z*F|-XKtJcv&2eTlwfBa->)ApbsUaiV<$K7h0R1v%yy0GzJH*v^7pwnZ;gKtBtm(rZ zcMUl#{Q#tB1p!!U2!u2yuMhhbeKZ6Z+%DG|@MA+w?nHbSViCBB z7NfL4djd8`=G}(H+btK#b_>3d(K7tG zTK@3=v5D+7VkWy6*wvta$Pp?wJaO7$fzSq4^fk5v0_??!Z>!6{aO8VuJ^YTk@Me{W2pJ3ZXxgisfFg2e%p}^0)mF zB2V=P@zg)bBG8wb6n*+#M&x6{5PAGJxf-?r;jpH+(ogz(d8HQ&@n)YS=yplaYb6d^ zoD>|!O}TYLd9cC@MrZ~moIWQ9ck1YtCs9uEf-c4PJMrYZkidvkPe08MC4d1Z0p?+H zdzgYK(E$==3_2Oh`J4$;P?EhvyOlBIWZ-@+P!uf?I^cC#B6UXwfl!)HFimqn8N*Hn zT{i_x!szdSl^qEqm%(6|#tJvfl`-OE;6xcvM8FMHbtR^xQ6~w|9<|S+>FMr;jTwpE zJ|_)FiU>v&6eTY9;_k0-_B%N%a7&nQL_)`f3)R9n;AEWQ0VL6aeU!kI{hdw%&j0k_ zfRRLNh|FIZ&RtFp&I$=o0t#;H*w>*k8*`Fi%86h^p(YTR8gS6bz=0tgdlo`K#waB5 zhcXC+62jF1>>mi>p-uu{s3W|Lf&$Mw;erAl|4qVvj;tJ(S9<~V9#>p(Ma%B1G|an2 z$ZJx42B?QOdxZDP6+fU3hlpK`+DseR(EAfz(HemUopAVt#a@YFAtQz+2au?Z%Iz*= zkrHk#7FxR6`c=fZhNF{w&)PUtY&dgPt+z5op7vQaKYW6VNMDE^C>=-y~rV(-+sjBDhAbK4_2E%R_1gDlUB6+_KGmi@N)15 z=40E)4|;QSR6r#l*J=2EeJX6c{Br6gtpM|}0UuW}z57LV1M+n#B+^Y~3SA>do2;D2 zyG?=*OQ06{80mLq8+`X-)w(dF9l+Hp;U1CjQEQyf z*0$mwEtlqnNX-;Z?xn5Og!~CB`Am=7nIBZ)kF3Tb>MgskQEFYNpR`iB3grp`>TY+b zex!ku8WLbbSZl56)!MEMKj^3{t0}BAtSp3e2I?JlQ{d&dE{W__;!z=f#u`aff=*tJ zlrHE><;)A`(=Lv!k31$EYadB<0BTcdW{&%=+e-`M)k19oRa^sH5b`E#>Q1AUSe=K` zZ@Tn*1x_ZdQuU3h3>Y17LDz`7oBM=8bu-1F*uexu;b?h^&fQSU7%tHP3CYM|jpO|y zVwFt<1$w5pr|Jj0e4HF9X$>8k8a1WN~8|brfm?0Uwmu z9#qmJg!E1;34Pmke@_)Olw`|xr94t7@3K)Sk1*KEtkSCYKT6nSv?`gy8G8StogBN~ z{}?CUq4z)5NpR`?k8?6ydjI2{42RzTgbadR?|-6`;nMq`l)GW7mGags9i z{--!;ZoU6cogA0m|7T8yL+}4{C&8`vKh?>}(EFd}B)Rndzi=`fdjDT$5RBHl+>7b` zf8``t_5Qzh!V`KwtW-f~^sHL{(?!G|to5%;X#G*2{|u3DS&0y9edyCNwf<)c-#Vi4 zcq@ZMj*iaKY($3lX9>%xS3(meg|=n4QPiF-gxA};-SQ^UexV1DN~u8^=5vJkMk{l@ zFgs=fqb?cRbA|Q>D{YOppFEZN!ALdA$>#~NU5L-n_}CUJX|eT?w`{E>FA_lm z))-?d&@nL~R8m#r#1{*3&`LZDRf|<+4wWa#aqdfmJ7ndq_k!DSc0)pC>TMd=mkR9; zEA1?=yEzx&bT~Ap7`I!wFB9&lm5X$C^WoeW@lGYaT!^;&q`sj*(?4`=^)2I`&}LF{gw863+=N!`$ft&c%#_&^#eXwIaw}E zMBT{iT|&_llY$BBi8zbMbD2?07rAf}x%vhXfO|KKbWG~XQTvB+P>fm9Q6{)=6z=_2 zF6e8$u4d5Cwu-8vnf4~3-DRcms>mExifBCwEnYcq7S5QJvl`(vg7yxSepv6`B7}oh z0?dZv%sdlouZ-5AdGU53%vuRpPnZd?o*)?*W%@gWbhnj+B|$9J_fgBo@df@%(=YV7 zcQkRd((l9YRV&QUc**5r*2mr{LSJANdJg*BTvujpmtDzG{;|9bpcAYH`}fEdi9ZP|=ea_Q!?&6)PK65(`S> z&}D=-ra^u}NZ)XgX#ax(Skv8$-J}`XQR2|dO5Nv$^+6kp;thiW9BI0i^tGCn#?Z1X`1#Gp*_V)6BT5HuV0zgitW69+_0SXhv*sz z7gxK+{;MME16EmR1{??NnVD#&USAX94OSwp{8HQ(j{{#9(v3FKVRY(JnXz>muiI2> zuvSx@nV>Zh-l6p;@g(KAr`D!P`GyF8tW7wkSiDmUVo&XI74S_F@Hnf0 zvsD1juPd8|`iT53AwR)NMm5+(`%~B#O+?+4!hZ_+@mBI?-RPl^14_7Ti0rAECiiV& zKhetOpo19Dg zk0a}}5fqqi?t4Oigq4oCpGgyO96zou#3OI=?fb%hq?Nq^lVV~93w~H=TGBrd-lMEM zgo=@7s8*%hP?(^gkWG01CA>#ld210~5OGWf|4=xOv2qX=dQzDVoBC{u^+!T{l8s1h z0@mZ_$bMhlJB-T3XX<=}KT*QzfI**52+$dX*tW>wvka^YM-~E7V6aX=$M0}n&w46P zDvz!g#YCG8ydO&xzhjFcYJAYqL@%JKl0?er#{VtMZ(EtPFIqrT!L4_g3oK(rQpo0v z)lY={Lo0bRl)dt-AM_0N`FwdA?VR(YM+^U_!v49Hjjoc_-fCrrPFYYsnvVWw!ux@X zN9zLHd73XgqZj^Mc;C13P``Ntkp>3nVH%_vf`1{@U!Aw_tKTF9&eJUf@>70j;s7#eBJkBBg9c@PO`IV4=Yb9^?hRXqTffU>5TfY|e z@2qU8XV7wex{+am?rIy+c>hMo52VP>e8A##KpV3SXxp3#J}J>E?g0_^z2g^mR;a#* z0uj4V;BQ6XcaLA-c{+o^{wR{`C;w?Qef)!h;mE^MEOBPJ#qn}{yL1U2h*G3IE?v85#g1Z;VR+6V&UD+TCBBQ$B7#n{)pu$zm}jNV_nju3 zKX|9ldcJR!2+!Q+L%filaP}2Hqqkb%h}SA-&T|!g`VAz|$t7yvs(RK5<>FZbZW&6=R}DJX6Ftvll%9 z@A&g@k<&6cOGq26-6*0f=X;rAH1e~Bve8D7F5I+~jL2@zh%5w&7@pATJc;8*Cwv#H$qN3(h(|67FinT_m`V zS>mVyFiGE-zoSDt;t-i_;>(U z3E=`OL1NG6a3wld3p$-Mn4FxK$^g9lSn4GejggB(x+3=)k()+C#Q7-^c$tm?$u$`g zi}AG?lC3dbN^%(I>qK%I?}~Febrffqp>8{%*>Jsxv?{9%yhDLE2+-c3;3^c|POLuP zDCke6G7>F;?l(%-2`N^wACf^sb>T*a?#MLAT>}4nDiq|$7g8@J>2ym&YQRmxwvIta z`tBWORJd7y)^SIAJrki@1ZfYO`x4XR-YUq?Ibzw-X8ODi0e;#EG|A}{;Hy(W?R-qh zn^bjW;7^7SgEwPdcLx5H7~YIiJsJ3AF}%r<-5L1hF}xXJ_GIA6MuCa{bz0neGw^it z-QcfRd~XK+)EM5B{cRcemKc7w%D-Lk>A?)1|?=84@s+YZ?rqHLvV2-WC3iP1@U1L=`;H`;Eh0gm5JTLIo zRyfRCWB)^dcMH%u=cZ-@7Yn^`BRnz)$J5kwxDAm(2>gTPws0MQ*BS7hMmg993*XBu zEM2?>3D-JX57A+fjSJd3K}W~Y)pk&mQxu?eQeHjT+pe$)fxQcnO*b^MUL%=P%7Vdf z3l5VBa8iJ2_AJs$BS_Tw9C3tJ!$ycN)>reIIi5JeqbLosvEh3qmPp=>#+$f&Y z#}&`6wl0llS@6~s08~(PUO2ZZS#UTDN=1}Y;1K~@7b0k`X2$oK3>;+-d8HnOd-ono z{;cuL%0!}G;!v7iS=4G7&zo5ZFI|QROu|#2;MVZWs>7o2%YkgfX-qOzK5QWNAGQ^6nsGEt9~N9r!Ah?2G3B`BjoHiZ7VR8XK> zH*P`4oZirzLVsO0V|Fr8svf?FSa6S z)Qydd_X>8I6`LAI?-TTCR`g=^>V5&+)vNTN`!Ip8vdT_qV-FW3>HF!9pVAl8#vUQq z;nxnISjbeK_TsERMzauQDX3JF(-C9LD*tGbE=wF{fl%&+Up@-P1*G zVC}DHm3B{iS6i$#JwxzYt#}z2=$wft=g$=ISOz%KL z-w3+jil$jm6zLZT^gB*ylo@|3&^{{^m+Wy4O@e=+0AFYYVwHf8tO@i*0)0^m3T21J z8XEg(pD7alVqv^I#ULmtE{U9YiJ-f!XljPJB>ts>-($r~{}o>kd6~e69B}EMqeYIF z3w*!GtZJvjvJ z$eS&JHwpA9sd!?Ec}G~8JMv~O_~s1!&KTaz$lj8Hzbb||TLOQVfxkM2H(LU4&A?w1 z!<#LEw`Jh3jp5Dw@9i1*>tc8_yL(3l{`wf+Yze$G1AjvdZ}xiLm4Rp9cij05h2{Hh z!9O{>e22pFeNP5HD&L{JDc|>I;G^;#%A4|iUj{xZ-=VxI-@nhmN98+|H|6{O4183+ zLwQraAIQK*=5d{n+ec~ib0%D_kEJCrx&`{4|{lrQxO-P$L7M9`zD(xst= zfMzG@9|ZUwCvcBS{6_)4&k5{R;6DlQGfv=b3jAjQ-r)qAJ*IyV;QO7xewFyI0(_ej zXf~w(O@J?O0?iWrzYFlaPN3Oi`=|izV-{ujof^lF3Gh~j#133`7JcI50xUX#oeKPf z0Idt!o!nE<^0yhNJ}GF|K-Cdep-*Lq?GDBEXe2(Jfo3bMsC5|S75y1OyT-PTHdC2C zE5L#?6HI0LoB(fd0&mx#KQF+N6WFJ~{}3P=j70~g#0)C%3j(y}|6rI=rbc~H&@XX{ z&8gTgWr)p%Vn-GIWkHWS#70{HUlHKDtw5T)4CbK*sMN0t_}iIaQ?tG%VCy9!%mPHR zsV`p_u=UPR2sX9g8v?d#_C~Vl1imR?a&VhmW?Xc6i+V!g=GqPSTf$A-wTr;f_T7I9 z_y?JpV@mVe0{(R-*mNe}5%2?f7Vi8x-8_`KOrVd=fEuaG z1^W05=;fLND+Kzu45&GIuu`B;azH7wjMP&F`h*Oqk=i2ACt9J@1h#2RPZQvWoIum_ zt`gvfoj?=xY5{)G0qlYm5a~$Q2=J>`pj18sJzbz*u|lbpn9g~v0Kee?c7%bi6X4gJ zKqK)C0e;;IOfI&q7w8L9P}J~|)XNE8eZ&23J_?ZUvfp&vATrYmH)P&vlj$-ewowFG zwOcYcOeVhMJ|Qh$9$`IYlW?qRdD(gW@l0V^SAcQTe<1h{e>_JB*5e4ccxSo(c&;$4rwS+tWM?m18)Dml zEi|G_A)F_~oHbn=yRUG1G3(F-KJQ`gxFj|@`6ZhE;W{9V0< zZHx?DDC`z18^+N_7UoLqShVK*yGBL~-P|4bg?^fiPRUs#$?2=Y(>0~$T=qm%uE6j> zwE~IVy9bO&V>*yac0{S%tfe2V<6>tGArNM4TWyC1ry_Wd^n(sW%PV%t%LPpY|Lb?WQ-qM&w;&lLsS9u-n2m zX%LgHj-ip>LG3#`+D+GUtq9m+6#zS_(%vX3BYUMlI@*n`uIq$*v5PwlgCG2F*N8Uv zj&@_c<$B>>;^KA}8U^KQ7Iw6o{{9BxUTWh~Cbn=Uvdt~3ov^Z1n1b<@X^|IpenY;m zb?ZhEc&<%g`2w_%O35FG$)?~4iP+VtsgW&88T=n2A~rijutSn7W=If8*sBtPc6!uU z>=F^@SVh2&*u~JubdVQ2L3JW0|Ix|rq&fhaj-@cPOV))fET1g&GR+LTU`0ir3?h0W zgGS8KPMJv5o7h4KS>$_If&!8fB~?6&L!LmHqRj$I*o817UV`;4^1w|7#Qa@D!{M;H zJIvCXBume;X6Y6*4~(kZZ*lZ?b>Y-*j}{FZfzgt=S;U-g6@%Dp@j5ES=_*Va55QRs zWbNwk2Ri!02n~c0xiXq6O-*$bmblOksCaL;aOcU|p!Lov6C7~d)e5!&o^Lg6X; z6V+mK7HMP!Ft`#THANjF;3S&>86)U8be?kkf7>3-3Y2w#U}1HFg6C%ZhZ?DAs7DUf zqM>M0HH?y2rI~iWPIo&cZ>%fw{j_vW8H5Ar@S>N8rz^@|nBc@kd}#(P(@;^4X+C#} ztX5k-%VduEFp1RT7nRd3oXcz+3VNLhx&m`*%_0R38$R9DmWiqfwns#?*+d|w-7qb) ze;VEvS|;WVWw%h;Gbp2#MtP=XqG>35gtE;_S;wL5uEN4&sn#+vX-Ip8bcK}!>jAx! z?IY8rN_)=?oR*bCTCdQyTWMrA0n^Q5qorP&F#+8sj4N#nsp3+CFh<8tCcEf|bmq4U z_4%m@*-0?j*3sAJ!$Wq-AA{jN_=c}zUUG=)1SX#(!w&|HHH|)}oGl_}aKJBCE3jlv zbDJ^hGW-TcDiSXuv4~3|2ZPB;ja$D{<_49ydv_$%R99T9pz1n+-k?@4N`)y;l~H#j z#RE>M=XnF8aF*EH<#+e)=^e?XlMM?ZDCSv}H0YFcZ76B?;Bdb`1|!<&Z+mw`^!OUB_`k3Tj#1b>c){Ep#0{unt)C+po3H#9!d5PD6i4?BhVi-h$d z$-M)MLsT@#!sf5(s}3#A?Gi4sx2IOCn)>w6rHMU4#4_S;xCCz2OhwNx zP2DY2EHdYD}s^!Nnh$EoUtT&TObwYl|&8rCsKAba%sBFpWl) zqh%~kkruZ7D0NMT61@!9A=p2t1*Wf`bV^<8rF(ZWdB~ap^u?sU&|Rw<7cNsykuZ8Y zJUHYZEy&_mJ1tFclvap~RZZ!%Q@}c}=RofW4TSOLewxR14DZa+MA<1}lh;eL8qAMU zVovpXQBzS%H5!MVLe_X#_Z;pR>0#A}Q?SzOgL8qShI_=xUFG%lbnJ^UQQHOvhcwI? zCvTZYDAW{Kqh!S;faZdUYEqLy9W>@Cr4ycY3f$lg@)}5PQFfBiInfF*(PZhWBdo$K zvsw&F6H!M{aZ10~yU`yS9_;Gr9vz0h&~spD5PCzREp#&5k=$Y_@eO<1SVpxWIH6X7hnO+?bM-!H2pV zax(}OxMQf7Cu?d+JDwK}XFPmw_!uKwedUd9^Y5W-WL4e2j9UbzfV%4ym)dknJwK8v zyqHWC32!fZN)10Q@2FGW+DIOeBvO!&TO?uLDIpdkkhb}i(tMaom50*j*q9Z~V@_c$ zo&Z}-M23&;ZdQuqu}o|4f|GkGl0sl$Te-{G=EL4~bEdS-pF@-67O4?J4Pa<@5Ov7+ zIt6bqXn;ksib21^Vi4zASTpZ)%0bl*;R|s=RMpH-0b9VNBzBe?K?iQ9N&j@eQ|4Ae z0@#XqeYrBV!$&2PpF4ewYDhZ#SRB&$u4J);Mz?ubw$#B|tBT5&Dv>=9s!R`eifyIv z0X#mr=%vXiIQ$)GEe%7w9Q$O4lC&k2#f0VV%4&k4)fkpcMqn+|wF%N<+ z(@Nb7B;!9cMWfzq!zu?mo;PAorMXTym^2;gW1MoYWaQ*R80lJR5(}Ue_`{$;s=Ql3 zb&Va?Me+{>!-dL}$>+y9<)7^xU|{Q*2q3AY%7i38(KISY$r)tl&I2uh*}Qw4Q|u-J zw)*4cN};xpmo^c$gRY(3Ex}H$0*`mf*ysTmFa3(CNH}Xn(YQ)QJi#gAbOMGVOp$i) z>}m}stvXU9vm%f`0pn$b$UMc8J)?@3Pj83a^1GPM%cr~^AYTLQE9 z_hcu3tp{N1bm^Gno{9Vciu`q&@;}LBciGs;`s8mCU-5dgGY*}du*$Nu_Jjn#{tLN7rZC17j0g8GiO zg5}+9@MtqhI@e68GS!&YaSk@?Pzfw*w1n@JUQvYiS-61o+;;iE7T6|D z$-dSp5eHP@Cn(B+u=>U3N;on~ts^kn#_OEY&Jg6Zkrx&T_PBy*lk4?P0Rf+vN!H#m zI{88wSgbZHG#aVY7RC<3o3fV78=PXdDl}1lG0UI|Op-YSBNuCv2r%?&_C}}Fbqriw zgyP>`)BRAH8RQC)enQ}`A_S?h`P2PV0we#5lQ9{LS^i&Nx! zI4NS}qViqoiNh!@hre?Qz)~1FnKX3M)Tq_P>Kj}T1$=o%de65y#a$@2GL1M$(Wb`D zOREV^@1vZ}YWv%q!mz(ZIGxT$0({Cyt8Sw!peI48j(=h-7BU{78gOPw&%OxW|m_g@t^j5P#6joSW=^QCz zLz`;s&Z}YRxM^C|hnxaedLzC4J(?8glwIYcWz%Rr>||kYm{?o8qB&yEOkoZS2ATmM zS(0jI?g*12YR2n-SdzF`!$jNa!&!I@@E@1tndv?86EB8PC;ifTEL4XwTPrhz4(Mv%tZ_(6=QC?hGjRi&W!I)p2ruSgP57i!-svo_t})_-#io0m&GJkGv!BCQ5TZ@ElVTfkhhZbJic2ckCa>eb zPPo@j8z}fjqYx=AbeJdlh81Mmo#&N9^OhgTdm&bSu+CZ!L!p%*-ZzvPcDQdSk6@7I zPzf*{H9O4w0?%OO0x0OE*-#jb&lEIwdnRapptoF|%v*k-T+lYrU9KOY{YQxCuECWm zs?Maj;_xYF&YtV>9QP*Q(1_JKK?0=ykUF6P;XX_|r%yZOZSiIcbABWaoYpZGN9!Zd znRI|yOJZpl(~V6P{28a<&0ei2a)~9onyobI#iGgbMrtK9YJJuzturBwC@hOcP^zn? zS&1yFMV;b}bqN&WIQ^{XPYE_khC0TSj_7mFfOp7IN=>|wbTTM|cq({aFobc^g*t86 z_L%j~&pU%?^>CmAM`t9rn8S%fm&bcP=HP&&fF<__N1#V(8T^M+@>yZ7^%K4o8dO5( zKop0XQ53)66m)4Kip*IQMQl;U;uj3hM)CWiQ*0DJ#wX*)MMW7N6sLy@;p+I8oYF4y zsCrQXB`2k@h}t@b|4DICmP$l%qF|vug7cfK$PM7V=I584A+&J_BAu92e~H+N3dqMm zQQr^;EW1jpi7E2E12}Ae6JgNZ{3E3WoCb-`PJYE1;N^*Y@2!+u$8fEPl8LHan48;1 zvbK>hlP21d$L+wyL44I2M6zfdL5Os8ztWCLyk^$doPw`BzPN9Nx3r#-o*Px&h`gmD zdANHT_nP~4XISk^hBX$3qaE7WbS42g6${1>kS?R@YZ3P-0kOzQsA8QA);V~sdS0osW6oEibG zXWw=T+Ue14Rvy97cPfjP)}=AhViQ!p9f!7I^MQWdpb^GA3jN<;Zs)#|=}Eui3}n3r ztwRD4MmP;5A-S1oj{RMy3_X<(0^{LC9oa-l#tJ)x>@SoX)R{~SmBV8U-*XB}R*nSM z92IC_Dh5{xQCFl}3nRxGxgsvkLYqObUE%T4?>hs7PDXbf04Fp>nKQ2|Xx1X_@&``( zdEQ*LE}7TGjMlMQ6>F-+>Wr2JD=l5kpq7j6DEyaG;Mq}pnnLjh2e#wnaTGTidv6bW zsUJE;UFcC)X=)D`tz$i1dk41<4ALKs-UiMoT020-l}Z(IM6dPoM^4GxJXAK!G(>ok z+-lN~I*K_+JeZMEV1mivqPhn2V`nhuCwhq}7$Qq0rG7y*?EOPIGF!mqj$4e4(%|@E zoFCCZ{@WQycc@6np*Nwm7H10eI*q7UAE(X%^D``A$Q2eGO=&cF+ff(ZWDLRabyT`; zoHUuj0oYPaBz2J>jm1x#vA|HJL%WqP(UD-dNp)l07uVGn5{dk&Q@o$ZNomvi${I42BBEQXT;-{!#ZDjprlOV*xM_6N0%{t$>B2;HUSt1jXBbdD zG=HRN2rV-dPDg(g8w(O84dXY?FrswyR}E?D5OQ=TI}ySI&JZpNQ$b#bg`@>A*->Ap z=sG3G98RKxN=9bHh=d_VT$vfdMWJW)4|-~QLns-7T0jdkzS0_ zWkb3bX>17mPQts~cA@Vulx&(>`?*r>Xt{{pM>7HE2{(Nv?Wi;}Q>b8gj6So@#0vup zb*RDN6rVKr!!Y$iU8^tszn?pb^XJLo^f1o+qI-=68|!l^aX6DpiR&wm*RZ&Ocpa97 zfPj+cofM@#>aXR-E0&t+2moI$#ieeR629Q|5^QPe{ZCxu)$ide1QTFfo9CMqh9AB- zj3xOfO7Qx%IFk5I3LSOo(Ta#!!J(+??OEde?_UrOI9Odk`k%TW%rY$(g!w&R5H?0Q ze=il$dO>)Y`gQyl8tnlS*VgrFvA2P(sHIH=xeQOi#^j#%9=cDY5>CpHFr2!tiip5> z+I`ABS-3Aw!4P^fN+$s#+=nUmloR4Y;4)h%NxOU$3XscFND2Bf4SHEd(0_O+#&X&6 zKWZp9YFbuggpy0-LsSG8D|h7ybLm#Q@rZY-u+v7SPy%mFgp3C&7MCGQ7`jW;$QBWt zHqH+j$t00rDq8X36R*{$iHrdNl2%t;G9U(b`fuyl*WpogLw5D3(2MNOf`(Zg1OT8*c%!S5beaW=N|TLo-2 zq!@yGH5V=uu+?s22sSpnFBh=YN@55$?i$(zY_)$Ff{p3)Z34DhI}E|bIDNZ-t(FZ# zaF-_V3ISWK7=~bDNPoM4ttJaYaKB2vQovU8gdy12O5Y)1t0BS=Z2al$6tLCmpw^7C zM&c@gT8-c-w5iam1!}c+r_icGuMw!#terxQpWbT)YPDad(1uFAPM}spbqbwO==B1% zTBOtL>S#07@&*B0&CP{iQy*>=u+_9&2sU0i9wK0?Ex8bECSbb+Y&9Mif=%nVNx)WX zaSHBgGwz*l7O>SmR|qz7zD2-RD_kMiIIXx2T6n}@$Gi&z=2Ynm3D zpuhdNXf$XWBfv+Od1Mt!EOYk>z1ybNS#tMOQ2o}+{QGErm$Q-5x(bjMNu+_eWSn9X zZ1uajOpr>z1IeU`Z*mfd7 zn{w4W^T!T%|7mNx$2(w;l+WKyrToL8QCMs{?CCzcbXuHTW7?zA~YXI8H8 znpkKznK_&xG`+9j6uQhKQ;QPMT!zTB{lzSiu&XE{M>0gFjV)%04112z43TM*k69wa zv1ea~$h39G43W`rwm(B;+VZ1QoUsRN+^6u;tS`AZrlhjU^YlSh-VTnsyd}NLk%Vd>|67ad9DU zwjnRJy<90Tlbr)4G#ZjAnF#1W;w2vFS=HEjPZa=u)hxuhZpR~+7hFipdYUUG0%QXthOs?)ev7lCZ4{beIzx*=V-;^*9 z?pQKJ@-829eqN9uuT7U>2zyrQ6=YC}VKsl}^Q zo3k?oTysT+ObFWQd-O`mKTB4h?0tihdvHsE{uFT2+lBkN;HpdE9uQn}DclDI*Rd4t z(}EjZ3ik!UjV^`zvUk!7@4kce`om(#r=)Ti{&?B{XVkkP!;`%fdF;k?C$X*|&tn|oO>M] Use specified configuration file (no arg=builtin).\n" +#ifdef CONFIG_DESKTOP + " -D[<.dsk>] Load/Save desktop from <.dsk> file (no arg=disable desktop).\n" +#endif +#ifdef CONFIG_HISTORY + " -H[<.his>] Load/Save history from <.his> file (no arg=disable history).\n" +#endif + " -m[] Override mode for remaining files (no arg=no override).\n" + " -l[,] Go to line (and column) in next file.\n" + " -r Open next file as read-only.\n" +#ifdef CONFIG_TAGS + " -T[] Load tags file at startup.\n" + " -t Locate specified tag.\n" +#endif +// " -p Load files into already running FTE.\n" + ); +} + +#ifndef UNIX +/* + * findPathExt() returns a ^ to the suffix in a file name string. If the + * name contains a suffix, the pointer ^ts to the suffix' dot character, + * if the name has no suffix the pointer points to the NUL terminator of + * the file name string. + * .lib: CBASE.LIB + */ +static char *findPathExt(char *filename) { + char *p, *sps; + + for (p = filename, sps = NULL; *p; p++) { + if (ISSLASH(*p)) + sps = NULL; + if (*p == '.') + sps = p; + } + if (sps == NULL) + sps = p; + return sps; +} +#endif + +#if defined(NT) && defined(MSVC) +char *getProgramName(char *name) { + return _pgmptr; +} +#endif + +#if defined(OS2) && defined(__EMX__) + +// argv[0] on emx does not contain full path + +#define INCL_DOS +#include + +char *getProgramName(char *name) { + char ProgramName[MAXPATH]; + PTIB tib; + PPIB pib; + + DosGetInfoBlocks(&tib, &pib); + if (DosQueryModuleName(pib->pib_hmte, sizeof(ProgramName), ProgramName) != 0) + return name; + return strdup(ProgramName); +} + +#endif + +static int GetConfigFileName(int argc, char **argv, char *ConfigFileName) { + char CfgName[MAXPATH] = ""; + + if (ConfigFileName[0] == 0) { +#if defined(UNIX) + // ? use ./.fterc if by current user ? + ExpandPath("~/.fterc", CfgName); +#elif defined(DOS) || defined(DOSP32) + strcpy(CfgName, argv[0]); + strcpy(findPathExt(CfgName), ".cnf"); +#elif defined(OS2) || defined(NT) + char home[MAXPATH] = ""; + char *ph; +#if defined(OS2) + ph = getenv("HOME"); + if (ph) strcpy(home, ph); +#endif +#if defined(NT) + ph = getenv("HOMEDRIVE"); + if (ph) strcpy(home, ph); + ph = getenv("HOMEPATH"); + if (ph) strcat(home, ph); +#endif + if (home[0]) { + strcpy(CfgName, home); + Slash(CfgName, 1); + strcat(CfgName, "fte.cnf"); + } + + if (!home[0] || access(CfgName, 0) != 0) { + strcpy(CfgName, argv[0]); + strcpy(findPathExt(CfgName), ".cnf"); + } +#endif + + strcpy(ConfigFileName, CfgName); + } + if (access(ConfigFileName, 0) == 0) + return 1; + +#if defined(UNIX) + for (unsigned int i = 0; i < sizeof(Unix_RCPaths)/sizeof(Unix_RCPaths[0]); i++) { + if (access(Unix_RCPaths[i], 0) == 0) { + strcpy(ConfigFileName, Unix_RCPaths[i]); + return 1; + } + } +#endif + return 0; +} + +static int CmdLoadConfiguration(int &argc, char **argv) { + int ign = 0; + int QuoteAll = 0, QuoteNext = 0; + int haveConfig = 0; + int Arg; + + for (Arg = 1; Arg < argc; Arg++) { + if (!QuoteAll && !QuoteNext && (argv[Arg][0] == '-')) { + if (argv[Arg][1] == '-') { + if (strcmp(argv[Arg], "--help") == 0) { + Usage(); + return 0; + } + int debug_clean = strcmp(argv[Arg], "--debugclean") == 0; + if (debug_clean || strcmp(argv[Arg], "--debug") == 0) { +#ifndef FTE_NO_LOGGING + char path[MAXPATH]; +#ifdef UNIX + ExpandPath("~/.fte", path); +#else + JustDirectory(argv[0], path); +#endif + Slash(path,1); + strcat(path, "fte.log"); + if (debug_clean) unlink(path); + + globalLog.SetLogFile(path); + printf("Trace Log in: %s\n", path); +#else + printf("--debug, --debugclean disabled\n"); +#endif + } + else + QuoteAll = 1; + } else if (argv[Arg][1] == '!') { + ign = 1; + } else if (argv[Arg][1] == '+') { + QuoteNext = 1; + } else if (argv[Arg][1] == '?' || argv[Arg][1] == 'h') { + Usage(); + return 0; + } else if (argv[Arg][1] == 'c' || argv[Arg][1] == 'C') { + if (argv[Arg][2]) + { + strcpy(ConfigFileName, argv[Arg] + 2); + haveConfig = 1; + } + else + ign = 1; + } + } + } + if (!haveConfig && GetConfigFileName(argc, argv, ConfigFileName) == 0) { + // should we default to internal +#ifdef DEFAULT_INTERNAL_CONFIG + ign = 1; +#endif + } + + if (ign) { + if (UseDefaultConfig() == -1) + DieError(1, "Error in internal configuration??? FATAL!"); + } else { + if (LoadConfig(argc, argv, ConfigFileName) == -1) + DieError(1, + "Failed to load configuration file '%s'.\n" + "Use '-C' option.", ConfigFileName); + } + for (Arg = 1; Arg < argc; Arg++) { + if (!QuoteAll && !QuoteNext && (argv[Arg][0] == '-')) { + if (argv[Arg][1] == '-' && argv[Arg][2] == '\0') { + QuoteAll = 1; + } else if (argv[Arg][1] == '+') { + QuoteNext = 1; +#ifdef CONFIG_DESKTOP + } else if (argv[Arg][1] == 'D') { + ExpandPath(argv[Arg] + 2, DesktopFileName); + if (IsDirectory(DesktopFileName)) { + Slash(DesktopFileName, 1); + strcat(DesktopFileName, DESKTOP_NAME); + } + if (DesktopFileName[0] == 0) { + LoadDesktopOnEntry = 0; + SaveDesktopOnExit = 0; + } else { + LoadDesktopOnEntry = 1; + } +#endif +#ifdef CONFIG_HISTORY + } else if (argv[Arg][1] == 'H') { + strcpy(HistoryFileName, argv[Arg] + 2); + if (HistoryFileName[0] == 0) { + KeepHistory = 0; + } else { + KeepHistory = 1; + } +#endif + } + } else { + if (LoadDesktopOnEntry == 2) { + LoadDesktopOnEntry = 0; + SaveDesktopOnExit = 0; + DesktopFileName[0] = 0; + } + } + } + if (LoadDesktopOnEntry == 2) + LoadDesktopOnEntry = 1; + return 1; +} + +int main(int argc, char **argv) { +#if defined(_DEBUG) && defined(MSVC) && defined(MSVCDEBUG) + _CrtSetReportMode( _CRT_WARN, _CRTDBG_MODE_FILE ); + _CrtSetReportFile( _CRT_WARN, _CRTDBG_FILE_STDERR ); + _CrtSetReportMode( _CRT_ERROR, _CRTDBG_MODE_FILE ); + _CrtSetReportFile( _CRT_ERROR, _CRTDBG_FILE_STDERR ); + _CrtSetReportMode( _CRT_ASSERT, _CRTDBG_MODE_FILE ); + _CrtSetReportFile( _CRT_ASSERT, _CRTDBG_FILE_STDERR ); +#endif //_DEBUG && MSVC && MSVCDEBUG + +#if defined(__EMX__) || (defined(NT) && defined(MSVC)) + argv[0] = getProgramName(argv[0]); +#endif + +#if defined(UNIX) && defined(LINUX) + // security fix - when we need to be suid to access vcsa + effuid = geteuid(); + effgid = getegid(); + + if (getuid() != effuid) + seteuid(getuid()); + if (getgid() != effgid) + setegid(getgid()); +#endif + + if (CmdLoadConfiguration(argc, argv) == 0) + return 1; + + STARTFUNC("main"); + + EGUI *g = new EGUI(argc, argv, ScreenSizeX, ScreenSizeY); + if (gui == 0 || g == 0) + DieError(1, "Failed to initialize display\n"); + + gui->Run(); + +#if defined(OS2) && !defined(DBMALLOC) && defined(CHECKHEAP) + if (_heapchk() != _HEAPOK) + DieError(0, "Heap memory is corrupt."); +#endif + + delete gui; + gui = 0; + +#if defined(__EMX__) + free(argv[0]); +#endif + +#if defined(OS2) && !defined(DBMALLOC) && defined(CHECKHEAP) + if (_heapchk() != _HEAPOK) + DieError(0, "Heap memory is corrupt."); +#endif + +#if defined(_DEBUG) && defined(MSVC) && defined(MSVCDEBUG) + _CrtSetDbgFlag((_CRTDBG_LEAK_CHECK_DF) | _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG)); +#endif //_DEBUG && MSVC && MSVCDEBUG + +#if defined(__DEBUG_ALLOC__) + _dump_allocated(64); +#endif + + ENDFUNCRC(0); + //return 0; +} diff --git a/src/fte.def b/src/fte.def new file mode 100644 index 0000000..834220e --- /dev/null +++ b/src/fte.def @@ -0,0 +1,3 @@ +NAME fte WINDOWCOMPAT +DESCRIPTION 'FTE Text Editor' +STACKSIZE 49152 diff --git a/src/fte.h b/src/fte.h new file mode 100644 index 0000000..9ef40e2 --- /dev/null +++ b/src/fte.h @@ -0,0 +1,64 @@ +/* fte.h + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#ifndef __FTE_H +#define __FTE_H + +#include "ftever.h" +#include "feature.h" +#include "sysdep.h" + +#ifdef NEED_LOG_H +#include "log.h" +#endif // NEED_LOG_H +#include "console.h" +#include "gui.h" +#include "c_desktop.h" +#include "e_regex.h" +#include "c_mode.h" +#include "c_hilit.h" +#include "c_bind.h" +#include "e_undo.h" +#include "c_color.h" +#include "s_files.h" +#include "s_direct.h" +#include "c_config.h" +#include "c_fconfig.h" +#include "i_oview.h" +#include "i_input.h" +#include "i_key.h" +#include "i_choice.h" +#include "i_ascii.h" +#include "i_view.h" +#include "i_modelview.h" +#include "egui.h" +#include "o_model.h" +#include "e_buffer.h" +#include "e_mark.h" +#include "o_list.h" +#include "e_tags.h" +#include "s_util.h" +#include "i_search.h" +#include "i_complete.h" +#include "o_directory.h" +#include "o_messages.h" +#include "o_buflist.h" +#include "o_routine.h" +#include "o_modemap.h" +#include "c_commands.h" +#include "c_history.h" + +#if defined(_DEBUG) && defined(MSVC) && defined(MSVCDEBUG) +#include + +#define new new( _CLIENT_BLOCK, __FILE__, __LINE__) + +#endif //_DEBUG && MSVC && MSVCDEBUG + +#endif diff --git a/src/fte2.cpp b/src/fte2.cpp new file mode 100644 index 0000000..ad113ba --- /dev/null +++ b/src/fte2.cpp @@ -0,0 +1,525 @@ +/* fte.cpp + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#include "fte.h" + +#if defined(UNIX) +/* Some paths where to also look for the rc-file */ +/* How many */ +#define UNIX_RCPATHS 3 + +/* Actual locations */ +char *Unix_RCPaths[UNIX_RCPATHS]={ + "/usr/local/etc/fte/system.fterc", + "/etc/fte/system.fterc", + "/usr/X11R6/lib/X11/xfte/system.fterc", +}; + +#endif /* UNIX */ + +static void Usage() { + printf("Usage: " PROGRAM " [-!] [-?] [--help] [-h] [-crdnm] files...\n" + "Version: " VERSION " " COPYRIGHT "\n" + " You may distribute under the terms of either the GNU General Public\n" + " License or the Artistic License, as specified in the README file.\n" + "\n" + "Options:\n" + " -- End of options, only files remain.\n" + " -+ Next option is file.\n" + " -? Display usage.\n" + " -h Display usage.\n" + " --help Display usage.\n" + " -! Ignore config file, use builtin defaults (also -c).\n" + " -c[<.cnf>] Use specified configuration file (no arg=builtin).\n" +#ifdef CONFIG_DESKTOP + " -d[<.dsk>] Load/Save desktop from <.dsk> (no arg=disable desktop).\n" +#endif +/* +#ifdef CONFIG_HISTORY + " -h[<.his>] Load/Save history from <.his> (no arg=disable history).\n" +#endif +*/ + " -m[] Override mode for remaining files (no arg=no override).\n" + " -l[,] Go to line (and column) in next file.\n" + " -r Open next file as read-only.\n" +#ifdef CONFIG_TAGS + " -T[] Load tags file at startup.\n" + " -t Locate specified tag.\n" +#endif +// " -p Load files into already running FTE.\n" + ); +} + +/* + * findPathExt() returns a ^ to the suffix in a file name string. If the + * name contains a suffix, the pointer ^ts to the suffix' dot character, + * if the name has no suffix the pointer points to the NUL terminator of + * the file name string. + * .lib: CBASE.LIB + */ +static char *findPathExt(char *filename) { + char *p, *sps; + + for (p = filename, sps = NULL; *p; p++) { + if (ISSLASH(*p)) + sps = NULL; + if (*p == '.') + sps = p; + } + if (sps == NULL) + sps = p; + return sps; +} + +#if defined(OS2) && defined(__EMX__) + +// argv[0] on emx does not contain full path + +#define INCL_DOS +#include + +char *getProgramName(char *name) { + char ProgramName[MAXPATH]; + PTIB tib; + PPIB pib; + + DosGetInfoBlocks(&tib, &pib); + if (DosQueryModuleName(pib->pib_hmte, sizeof(ProgramName), ProgramName) != 0) + return name; + return strdup(ProgramName); +} + +#endif + +static int GetConfigFileName(int argc, char **argv, char *ConfigFileName) { + int i; + char CfgName[MAXPATH] = ""; + + if (ConfigFileName[0] == 0) { +#if defined(UNIX) + // ? use ./.fterc if by current user ? + ExpandPath("~/.fterc", CfgName); +#elif defined(DOS) || defined(DOSP32) + strcpy(CfgName, argv[0]); + strcpy(findPathExt(CfgName), ".cnf"); +#elif defined(OS2) || defined(NT) + char home[MAXPATH] = ""; + char *ph; +#if defined(OS2) + ph = getenv("HOME"); + if (ph) strcpy(home, ph); +#endif +#if defined(NT) + ph = getenv("HOMEDRIVE"); + if (ph) strcpy(home, ph); + ph = getenv("HOMEPATH"); + if (ph) strcat(home, ph); +#endif + if (home[0]) { + strcpy(CfgName, home); + Slash(CfgName, 1); + strcat(CfgName, "fte.cnf"); + } + + if (!home[0] || access(CfgName, 0) != 0) { + strcpy(CfgName, argv[0]); + strcpy(findPathExt(CfgName), ".cnf"); + } +#endif + + strcpy(ConfigFileName, CfgName); + } +// printf("Trying '%s'...",ConfigFileName); + if (access(ConfigFileName, 0) == 0) + { +// printf("success, loading!\n"); + return 1; + } +// printf("failed!\n"); + +#if defined(UNIX_RCPATHS) + for (i=0;iSwitchToModel(MM); + } else { + if (ModeOverride) { + if (MultiFileLoad(argv[Arg], Mode, 0) == 0) return 0; + } else { + if (MultiFileLoad(argv[Arg], 0, 0) == 0) return 0; + } + if (((EBuffer *)MM)->Loaded == 0) + ((EBuffer *)MM)->Load(); + if (GotoLine) { + GotoLine = 0; + ((EBuffer *)MM)->SetNearPosR(ColNum - 1, LineNum - 1); + } else { + int r, c; + + if (RetrieveFPos(((EBuffer *)MM)->FileName, r, c) == 1) + ((EBuffer *)MM)->SetNearPosR(c, r); + } + + if (ReadOnly) { + ReadOnly = 0; + BFI(((EBuffer *)MM), BFI_ReadOnly) = 1; + } + } + QuoteNext = 0; + MM = MM->Next; + LCount++; + } + } + while (LCount-- > 0) + MM = MM->Prev; + return 1; +} + +#ifdef CONFIG_HISTORY +static void DoLoadHistoryOnEntry(int &argc, char **argv) { + if (HistoryFileName[0] == 0) { +#ifdef UNIX + ExpandPath("~/.fte-history", HistoryFileName); +#else + JustDirectory(argv[0], HistoryFileName); + strcat(HistoryFileName, "fte.his"); +#endif + } else { + char p[256]; + + ExpandPath(HistoryFileName, p); + if (IsDirectory(p)) { + Slash(p, 1); +#ifdef UNIX + strcat(p, ".fte-history"); +#else + strcat(p, "fte.his"); +#endif + } + strcpy(HistoryFileName, p); + } + + if (KeepHistory && FileExists(HistoryFileName)) + LoadHistory(HistoryFileName); +} + +static void DoSaveHistoryOnExit() { + if (KeepHistory && HistoryFileName[0] != 0) + SaveHistory(HistoryFileName); +} +#endif + +#ifdef CONFIG_DESKTOP +void DoLoadDesktopOnEntry(int &argc, char **argv) { + if (DesktopFileName[0] == 0) { +#ifdef UNIX + if (FileExists(".fte-desktop")) { + ExpandPath(".fte-desktop", DesktopFileName); + } else { + ExpandPath("~/.fte-desktop", DesktopFileName); + } +#else + if (FileExists("fte.dsk")) { + ExpandPath("fte.dsk", DesktopFileName); + } else { + JustDirectory(argv[0], DesktopFileName); + strcat(DesktopFileName, "fte.dsk"); + } +#endif + } else { + char p[MAXPATH]; + + ExpandPath(DesktopFileName, p); + if (IsDirectory(p)) { + Slash(p, 1); +#ifdef UNIX + strcat(p, ".fte-desktop"); +#else + strcat(p, "fte.dsk"); +#endif + } + strcpy(DesktopFileName, p); + } + + if (LoadDesktopOnEntry && FileExists(DesktopFileName)) + LoadDesktop(DesktopFileName); +} +#endif + +static void EditorInit() { + SS = new EBuffer((EModel **)&SS, "Scrap"); + BFI(SS, BFI_Undo) = 0; // disable undo for clipboard + MM = 0; +} + +static void EditorCleanup() { + EModel *B, *N, *A; + EView *BW, *NW, *AW; + + if (MM) { + B = A = MM; + while (B != A) { + N = B->Next; + delete B; + B = N; + } + } + MM = 0; + + delete SS; + SS = 0; + + if (VV) { + BW = AW = VV; + while (BW != AW) { + NW = BW->Next; + delete BW; + BW = NW; + } + } + VV = 0; +} + +static int InterfaceInit(int &argc, char **argv) { + GxView *view; + ExModelView *edit; + + new EGUI(argc, argv, ScreenSizeX, ScreenSizeY); + if (gui == 0) + DieError(1, "Failed to initialize display\n"); + + new EFrame(ScreenSizeX, ScreenSizeY); + if (frames == 0) + DieError(1, "Failed to create window\n"); + + //frames->SetMenu("Main"); //?? + + view = new GxView(frames); + if (view == 0) + DieError(1, "Failed to create view\n"); + + VV = new EView(MM); + assert(VV != 0); + + edit = new ExModelView(VV); + if (edit == 0) return 1; + view->PushView(edit); + return 0; +} + +static void InterfaceCleanup() { + while (frames) + delete frames; + + delete gui; +} + +int main(int argc, char **argv) { +#if defined(__EMX__) + argv[0] = getProgramName(argv[0]); +#endif + + if (CmdLoadConfiguration(argc, argv) == 0) + return 1; + +#ifdef CONFIG_HISTORY + DoLoadHistoryOnEntry(argc, argv); +#endif + + EditorInit(); + +#ifdef CONFIG_DESKTOP + DoLoadDesktopOnEntry(argc, argv); +#endif + + if (CmdLoadFiles(argc, argv) == 0) + return 3; + + if (MM == 0) { +#ifdef CONFIG_OBJ_DIRECTORY + char Path[MAXPATH]; + + GetDefaultDirectory(0, Path, sizeof(Path)); + MM = new EDirectory(&MM, Path); + assert(MM != 0); + //VV->SwitchToModel(MM); +#else + Usage(); + return 1; +#endif + } + if (InterfaceInit(argc, argv) != 0) + return 2; + + gui->Run(); // here starts the PM second thread, so the above blocks the SIQ ;-( + +#ifdef CONFIG_HISTORY + DoSaveHistoryOnExit(); +#endif + + EditorCleanup(); + + InterfaceCleanup(); + +#if defined(OS2) + if (_heapchk() != _HEAPOK) + DieError(0, "Heap memory is corrupt."); +#endif + return 0; +} diff --git a/src/ftepm.def b/src/ftepm.def new file mode 100644 index 0000000..37c88c1 --- /dev/null +++ b/src/ftepm.def @@ -0,0 +1,3 @@ +NAME ftepm WINDOWAPI +DESCRIPTION 'FTE Text Editor - Presentation Manager GUI' +STACKSIZE 49152 diff --git a/src/ftepm.rc b/src/ftepm.rc new file mode 100644 index 0000000..3d537aa --- /dev/null +++ b/src/ftepm.rc @@ -0,0 +1,30 @@ +#include + +ICON 1 icons\ftepm.ico + +BITMAP 101 bmps\exit.bmp +BITMAP 102 bmps\open.bmp +BITMAP 103 bmps\save.bmp +BITMAP 104 bmps\close.bmp +BITMAP 105 bmps\prev.bmp +BITMAP 106 bmps\last.bmp +BITMAP 107 bmps\next.bmp +BITMAP 108 bmps\undo.bmp +BITMAP 109 bmps\redo.bmp +BITMAP 110 bmps\cut.bmp +BITMAP 111 bmps\copy.bmp +BITMAP 112 bmps\paste.bmp +BITMAP 113 bmps\pastecol.bmp +BITMAP 114 bmps\errprev.bmp +BITMAP 115 bmps\errnext.bmp +BITMAP 116 bmps\tagfind.bmp +BITMAP 117 bmps\tagnext.bmp +BITMAP 118 bmps\tagprev.bmp +BITMAP 119 bmps\tagpop.bmp + +MENU 1 +BEGIN + MENUITEM "Quit", 100 +END + +rcinclude pmdlg.rc diff --git a/src/ftever.h b/src/ftever.h new file mode 100644 index 0000000..2285f11 --- /dev/null +++ b/src/ftever.h @@ -0,0 +1,11 @@ +#ifndef __FTEVER_H +#define __FTEVER_H + +#define PROG_FTE "fte" +#define PROG_CFTE "cfte" +#define PROGRAM PROG_FTE +#define VERSION "0.49.13" +#define VERNUM 0x00490400UL +#define COPYRIGHT "Copyright (c) 1994-1998 Marko Macek\n" \ + "Copyright (c) 2000-2001 Others" +#endif diff --git a/src/g_draw.cpp b/src/g_draw.cpp new file mode 100644 index 0000000..00f02a1 --- /dev/null +++ b/src/g_draw.cpp @@ -0,0 +1,279 @@ +/* g_draw.cpp + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#include "console.h" + +#ifdef NTCONSOLE +# define WIN32_LEAN_AND_MEAN 1 +# include +#endif + +int CStrLen(const char *p) { + int len = 0, was = 0; + while (*p) { + len++; + if (*p == '&' && !was) { + len--; + was = 1; + } + p++; + was = 0; + } + return len; +} + +#ifndef NTCONSOLE + +void MoveCh(PCell B, char CCh, TAttr Attr, int Count) { + unsigned char *p = (unsigned char *) B; + while (Count > 0) { + *p++ = (unsigned char) CCh; + *p++ = (unsigned char) Attr; + Count--; + } +} + +void MoveChar(PCell B, int Pos, int Width, char const CCh, TAttr Attr, int Count) { + unsigned char *p = (unsigned char *) B; + if (Pos < 0) { + Count += Pos; + Pos = 0; + } + if (Pos >= Width) return; + if (Pos + Count > Width) Count = Width - Pos; + if (Count <= 0) return; + for (p += sizeof(TCell) * Pos; Count > 0; Count--) { + *p++ = (unsigned char) CCh; + *p++ = (unsigned char) Attr; + } +} + +void MoveMem(PCell B, int Pos, int Width, const char* Ch, TAttr Attr, int Count) { + unsigned char *p = (unsigned char *) B; + + if (Pos < 0) { + Count += Pos; + Ch -= Pos; + Pos = 0; + } + if (Pos >= Width) return; + if (Pos + Count > Width) Count = Width - Pos; + if (Count <= 0) return; + for (p += sizeof(TCell) * Pos; Count > 0; Count--) { + *p++ = (unsigned char) (*Ch++); + *p++ = (unsigned char) Attr; + } +} + +void MoveStr(PCell B, int Pos, int Width, const char* Ch, TAttr Attr, int MaxCount) { + unsigned char *p = (unsigned char *) B; + + if (Pos < 0) { + MaxCount += Pos; + Ch -= Pos; + Pos = 0; + } + if (Pos >= Width) return; + if (Pos + MaxCount > Width) MaxCount = Width - Pos; + if (MaxCount <= 0) return; + for (p += sizeof(TCell) * Pos; MaxCount > 0 && (*Ch != 0); MaxCount--) { + *p++ = (unsigned char) (*Ch++); + *p++ = (unsigned char) Attr; + } +} + +void MoveCStr(PCell B, int Pos, int Width, const char* Ch, TAttr A0, TAttr A1, int MaxCount) { + unsigned char *p = (unsigned char *) B; + + char was = 0; + if (Pos < 0) { + MaxCount += Pos; + Ch -= Pos; + Pos = 0; + } + if (Pos >= Width) return; + if (Pos + MaxCount > Width) MaxCount = Width - Pos; + if (MaxCount <= 0) return; + for (p += sizeof(TCell) * Pos; MaxCount > 0 && (*Ch != 0); MaxCount--) { + if (*Ch == '&' && !was) { + Ch++; + MaxCount++; + was = 1; + continue; + } + *p++ = (unsigned char) (*Ch++); + if (was) { + *p++ = (unsigned char) A1; + was = 0; + } else + *p++ = (unsigned char) A0; + } +} + +void MoveAttr(PCell B, int Pos, int Width, TAttr Attr, int Count) { + unsigned char *p = (unsigned char *) B; + + if (Pos < 0) { + Count += Pos; + Pos = 0; + } + if (Pos >= Width) return; + if (Pos + Count > Width) Count = Width - Pos; + if (Count <= 0) return; + for (p += sizeof(TCell) * Pos; Count > 0; Count--) { + p++; + *p++ = (unsigned char) Attr; + } +} + +void MoveBgAttr(PCell B, int Pos, int Width, TAttr Attr, int Count) { + char *p = (char *) B; + + if (Pos < 0) { + Count += Pos; + Pos = 0; + } + if (Pos >= Width) return; + if (Pos + Count > Width) Count = Width - Pos; + if (Count <= 0) return; + for (p += sizeof(TCell) * Pos; Count > 0; Count--) { + p++; + *p = ((unsigned char)(*p & 0x0F)) | ((unsigned char) Attr); + p++; + } +} + +#else + +void MoveCh(PCell B, char Ch, TAttr Attr, int Count) { + PCHAR_INFO p = (PCHAR_INFO) B; + while (Count > 0) { + p->Char.AsciiChar = Ch; + p->Attributes = Attr; + p++; + Count--; + } +} + +void MoveChar(PCell B, int Pos, int Width, const char Ch, TAttr Attr, int Count) { + PCHAR_INFO p = (PCHAR_INFO) B; + if (Pos < 0) { + Count += Pos; + Pos = 0; + } + if (Pos >= Width) return; + if (Pos + Count > Width) Count = Width - Pos; + if (Count <= 0) return; + for (p += Pos; Count > 0; Count--) { + p->Char.AsciiChar = Ch; + p->Attributes = Attr; + p++; + } +} + +void MoveMem(PCell B, int Pos, int Width, const char* Ch, TAttr Attr, int Count) { + PCHAR_INFO p = (PCHAR_INFO) B; + + if (Pos < 0) { + Count += Pos; + Ch -= Pos; + Pos = 0; + } + if (Pos >= Width) return; + if (Pos + Count > Width) Count = Width - Pos; + if (Count <= 0) return; + for (p += Pos; Count > 0; Count--) { + p->Char.AsciiChar = *Ch++; + p->Attributes = Attr; + p++; + } +} + +void MoveStr(PCell B, int Pos, int Width, const char* Ch, TAttr Attr, int MaxCount) { + PCHAR_INFO p = (PCHAR_INFO) B; + + if (Pos < 0) { + MaxCount += Pos; + Ch -= Pos; + Pos = 0; + } + if (Pos >= Width) return; + if (Pos + MaxCount > Width) MaxCount = Width - Pos; + if (MaxCount <= 0) return; + for (p += Pos; MaxCount > 0 && (*Ch != 0); MaxCount--) { + p->Char.AsciiChar = *Ch++; + p->Attributes = Attr; + p++; + } +} + +void MoveCStr(PCell B, int Pos, int Width, const char* Ch, TAttr A0, TAttr A1, int MaxCount) { + PCHAR_INFO p = (PCHAR_INFO) B; + char was; + //TAttr A; + + if (Pos < 0) { + MaxCount += Pos; + Ch -= Pos; + Pos = 0; + } + if (Pos >= Width) return; + if (Pos + MaxCount > Width) MaxCount = Width - Pos; + if (MaxCount <= 0) return; + was = 0; + for (p += Pos; MaxCount > 0 && (*Ch != 0); MaxCount--) { + if (*Ch == '&' && !was) { + Ch++; + MaxCount++; + was = 1; + continue; + } + p->Char.AsciiChar = (unsigned char) (*Ch++); + if (was) { + p->Attributes = A1; + was = 0; + } else + p->Attributes = A0; + p++; + } +} + +void MoveAttr(PCell B, int Pos, int Width, TAttr Attr, int Count) { + PCHAR_INFO p = (PCHAR_INFO) B; + + if (Pos < 0) { + Count += Pos; + Pos = 0; + } + if (Pos >= Width) return; + if (Pos + Count > Width) Count = Width - Pos; + if (Count <= 0) return; + for (p += Pos; Count > 0; Count--, p++) + p->Attributes = Attr; +} + +void MoveBgAttr(PCell B, int Pos, int Width, TAttr Attr, int Count) { + PCHAR_INFO p = (PCHAR_INFO) B; + + if (Pos < 0) { + Count += Pos; + Pos = 0; + } + if (Pos >= Width) return; + if (Pos + Count > Width) Count = Width - Pos; + if (Count <= 0) return; + for (p += Pos; Count > 0; Count--) { + p->Attributes = + ((unsigned char)(p->Attributes & 0xf)) | + ((unsigned char) Attr); + p++; + } +} + +#endif diff --git a/src/g_menu.cpp b/src/g_menu.cpp new file mode 100644 index 0000000..00a69d8 --- /dev/null +++ b/src/g_menu.cpp @@ -0,0 +1,80 @@ +/* g_menu.cpp + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#include +#include +#include +#include +#include +#include +#include "console.h" +#include "gui.h" + +int MenuCount = 0; +mMenu *Menus = 0; + +int NewMenu(const char *Name) { + int n; + + Menus = (mMenu *) realloc((void *) Menus, + sizeof(mMenu) * (MenuCount + 1)); + n = MenuCount; + + Menus[n].Name = strdup(Name); + Menus[n].Count = 0; + Menus[n].Items = 0; + + MenuCount++; + return n; +} + +int NewItem(int menu, const char *Name) { + int n; + + assert (menu < MenuCount); + + Menus[menu].Items = (mItem *) realloc(Menus[menu].Items, + sizeof(mItem) * (Menus[menu].Count + 1)); + n = Menus[menu].Count; + + Menus[menu].Items[n].SubMenu = -1; + Menus[menu].Items[n].Name = Name ? strdup(Name) : 0; + Menus[menu].Items[n].Arg = 0; + Menus[menu].Items[n].Cmd = -1; + + Menus[menu].Count++; + return n; +} + +int NewSubMenu(int menu, const char *Name, int submenu, int Type) { + int n; + + assert (menu < MenuCount); + + Menus[menu].Items = (mItem *) realloc(Menus[menu].Items, + sizeof(mItem) * (Menus[menu].Count + 1)); + n = Menus[menu].Count; + + Menus[menu].Items[n].SubMenu = submenu; + Menus[menu].Items[n].Name = Name ? strdup(Name) : 0; + Menus[menu].Items[n].Arg = 0; + Menus[menu].Items[n].Cmd = Type; + + Menus[menu].Count++; + return n; +} + +int GetMenuId(const char *Name) { + if (Name) + for (int i = 0; i < MenuCount; i++) + if (strcmp(Name, Menus[i].Name) == 0) + return i; + return -1; +} + diff --git a/src/g_motif.cpp b/src/g_motif.cpp new file mode 100644 index 0000000..0b1a9ab --- /dev/null +++ b/src/g_motif.cpp @@ -0,0 +1,2003 @@ +/* g_motif.cpp + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef HPUX +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "console.h" +#include "gui.h" + +#define DEBUG(x) +//printf x + +#define MAX_PIPES 4 +//#define PIPE_BUFLEN 4096 + +typedef struct { + int used; + int id; + int fd; + int pid; + int stopped; + EModel *notify; + XtInputId input; +} GPipe; + +static GPipe Pipes[MAX_PIPES] = { + { 0 }, { 0 }, { 0 }, { 0 } +}; + +#define sfFocus 1 + +static long MouseAutoDelay = 40; +static long MouseAutoRepeat = 200; +static long MouseMultiClick = 300; + +static Atom WM_DELETE_WINDOW; + +class GViewPeer { +public: + Widget ScrollWin; + Widget TextWin; + Widget SbHorz, SbVert; + GC gc[256]; + XGCValues gcv; + // TAttr GCattr; + int Visibility; + + GView *View; +// int wX, wY; + int wW, wH, wState, wRefresh; + int cX, cY, cVisible, cStart, cEnd; + int sbVstart, sbVamount, sbVtotal; + int sbHstart, sbHamount, sbHtotal; + int VertPos, HorzPos; + unsigned char *ScreenBuffer; + + GViewPeer(GView *view, int XSize, int YSize); + ~GViewPeer(); + + int AllocBuffer(); + void DrawCursor(int Show); + void UpdateWindow(int xx, int yy, int ww, int hh); + + int ConPutBox(int X, int Y, int W, int H, PCell Cell); + int ConGetBox(int X, int Y, int W, int H, PCell Cell); + int ConPutLine(int X, int Y, int W, int H, PCell Cell); + int ConSetBox(int X, int Y, int W, int H, TCell Cell); + int ConScroll(int Way, int X, int Y, int W, int H, TAttr Fill, int Count); + + int ConSetSize(int X, int Y); + int ConQuerySize(int *X, int *Y); + + int ConSetCursorPos(int X, int Y); + int ConQueryCursorPos(int *X, int *Y); + int ConShowCursor(); + int ConHideCursor(); + int ConCursorVisible(); + int ConSetCursorSize(int Start, int End); + + int QuerySbVPos(); + int SetSbVPos(int Start, int Amount, int Total); + int SetSbHPos(int Start, int Amount, int Total); + int ExpandHeight(int DeltaY); + + int UpdateCursor(); + int PMShowCursor(); + int PMHideCursor(); + int PMSetCursorPos(); +}; + +class GFramePeer { +public: + GFrame *Frame; + Widget ShellWin, MainWin, PanedWin, MenuBar; + + GFramePeer(GFrame *frame, int Width, int Height); + ~GFramePeer(); + + int ConSetTitle(char *Title, char *STitle); + int ConGetTitle(char *Title, int MaxLen, char *STitle, int SMaxLen); + + int ConSetSize(int X, int Y); + int ConQuerySize(int *X, int *Y); + void MapFrame(); +}; + +int ShowVScroll = 1; +int ShowHScroll = 0; +int ShowMenuBar = 1; +int ShowToolBar = 0; + +GFrame *frames = 0; +GUI *gui = 0; + +unsigned long HaveGUIDialogs = 0; + +static GView *MouseCapture = 0; +static GView *FocusCapture = 0; + +static int cxChar = 8; +static int cyChar = 13; + +static XtAppContext AppContext; +static Widget TopLevel; +static Display *display; +static Window root; +static int screen; +static Colormap colormap; +static XColor Colors[16]; +static XFontStruct *fontStruct; + +TEvent EventBuf = { evNone }; + +TEvent NextEvent = { evNone }; + +XButtonEvent LastRelease; +Widget LPopupMenu = 0; + +static int LastMouseX = -1, LastMouseY = -1; + +static void SetColor(int i) { + int j, k, z; + j = i & 7; + k = 65535 - 20480; + z = (i > 7) ? (20480) : 0; + Colors[i].blue = k * (j & 1) + z; + Colors[i].green = k * ((j & 2)?1:0) + z; + Colors[i].red = k * ((j & 4)?1:0) + z; + Colors[i].flags = DoRed | DoGreen | DoBlue; +} + +static int InitXColors() { + int i, j; + long d = 0, d1; + XColor clr; + long pix; + int num; + long d_red, d_green, d_blue; + unsigned long u_red, u_green, u_blue; + + for (i = 0; i < 16; i++) { + SetColor(i); + if (XAllocColor(display, colormap, &Colors[i]) == 0) { + SetColor(i); + pix = -1; + num = DisplayCells(display, DefaultScreen(display)); + for (j = 0; j < num; j++) { + clr.pixel = j; + XQueryColor(display, colormap, &clr); + + d_red = clr.red - Colors[i].red; + d_green = clr.green - Colors[i].green; + d_blue = clr.blue - Colors[i].blue; + + //fprintf(stderr, "%d:%d dr:%d, dg:%d, db:%d\n", i, j, d_red, d_green, d_blue); + + u_red = d_red / 10 * d_red; + u_green = d_green / 10 * d_green; + u_blue = d_blue / 10 * d_blue; + + //fprintf(stderr, "%d:%d dr:%u, dg:%u, db:%u\n", i, j, u_red, u_green, u_blue); + + d1 = u_red + u_blue + u_green; + + if (d1 < 0) + d1 = -d1; + if (pix == -1 || d1 < d) { + pix = j; + d = d1; + } + } + if (pix == -1) { + fprintf(stderr, "Color search failed for #%04X%04X%04X\n", + Colors[i].red, + Colors[i].green, + Colors[i].blue); + } + clr.pixel = pix; + XQueryColor(display, colormap, &clr); + Colors[i] = clr; + if (XAllocColor(display, colormap, &Colors[i]) == 0) { + fprintf(stderr, "Color alloc failed for #%04X%04X%04X\n", + Colors[i].red, + Colors[i].green, + Colors[i].blue); + } + } + } + return 0; +} + + +static struct { + long keysym; + long keycode; +} key_table[] = { + { XK_Escape, kbEsc }, + { XK_Tab, kbTab }, + { XK_Return, kbEnter }, + { XK_Pause, kbPause }, + { XK_BackSpace, kbBackSp }, + { XK_Home, kbHome }, + { XK_Up, kbUp }, + { XK_Prior, kbPgUp }, + { XK_Left, kbLeft }, + { XK_Right, kbRight }, + { XK_End, kbEnd }, + { XK_Down, kbDown }, + { XK_Next, kbPgDn }, + { XK_Select, kbEnd }, + { XK_KP_Enter, kbEnter | kfGray }, + { XK_Insert, kbIns | kfGray }, + { XK_Delete, kbDel | kfGray }, + { XK_KP_Add, '+' | kfGray }, + { XK_KP_Subtract, '-' | kfGray }, + { XK_KP_Multiply, '*' | kfGray }, + { XK_KP_Divide, '/' | kfGray }, + { XK_Num_Lock, kbNumLock }, + { XK_Caps_Lock, kbCapsLock }, + { XK_Print, kbPrtScr }, + { XK_Shift_L, kbShift }, + { XK_Shift_R, kbShift | kfGray }, + { XK_Control_L, kbCtrl }, + { XK_Control_R, kbCtrl | kfGray }, + { XK_Alt_L, kbAlt }, + { XK_Alt_R, kbAlt | kfGray }, + { XK_Meta_L, kbAlt }, + { XK_Meta_R, kbAlt | kfGray }, + { XK_F1, kbF1 }, + { XK_F2, kbF2 }, + { XK_F3, kbF3 }, + { XK_F4, kbF4 }, + { XK_F5, kbF5 }, + { XK_F6, kbF6 }, + { XK_F7, kbF7 }, + { XK_F8, kbF8 }, + { XK_F9, kbF9 }, + { XK_F10, kbF10 }, + { XK_F11, kbF11 }, + { XK_F12, kbF12 }, + { XK_KP_0, '0' | kfGray }, + { XK_KP_1, '1' | kfGray }, + { XK_KP_2, '2' | kfGray }, + { XK_KP_3, '3' | kfGray }, + { XK_KP_4, '4' | kfGray }, + { XK_KP_5, '5' | kfGray }, + { XK_KP_6, '6' | kfGray }, + { XK_KP_7, '7' | kfGray }, + { XK_KP_8, '8' | kfGray }, + { XK_KP_9, '9' | kfGray }, + { XK_KP_Decimal, '.' | kfGray }, + { 0x1000FF6F, kbDel | kfShift | kfGray }, + { 0x1000FF70, kbIns | kfCtrl | kfGray }, + { 0x1000FF71, kbIns | kfShift | kfGray }, + { 0x1000FF72, kbIns | kfGray }, + { 0x1000FF73, kbDel | kfGray }, + { 0x1000FF74, kbTab | kfShift }, + { 0x1000FF75, kbTab | kfShift }, + { 0, 0 } +}; + +void ConvertKeyToEvent(KeySym key, KeySym key1, char *keyname, int etype, int state, TEvent *Event) { + unsigned int myState = 0; + int i,k; + + + DEBUG(("key: \n")); + Event->What = evNone; + + switch (etype) { + case KeyPress: Event->What = evKeyDown; break; + case KeyRelease: Event->What = evKeyUp; break; + } + + if (state & ShiftMask) myState |= kfShift; + if (state & ControlMask) myState |= kfCtrl; + if (state & Mod1Mask) myState |= kfAlt; + if (state & Mod2Mask) myState |= kfAlt; + if (state & Mod3Mask) myState |= kfAlt; + if (state & Mod4Mask) myState |= kfAlt; + + DEBUG(("key: %d ; %d ; %d\n", key, key1, state)); + if (key < 256) { + if (myState == kfShift) myState = 0; + if (myState & kfCtrl) { + if (((key >= 'A') && (key < 'A' + 32)) || + ((key >= 'a') && (key < 'a' + 32))) + key &= 0x1F; + } + if (myState & kfAlt) { + if (((key >= 'A') && (key <= 'Z')) || + ((key >= 'a') && (key <= 'z'))) + key &= ~0x20; + } + Event->Key.Code = key | myState; + return; + } else { + for (i = 0; i < (sizeof(key_table) / sizeof(key_table[0])); i++) { + if (key1 == key_table[i].keysym) { + k = key_table[i].keycode; + if (k < 256) + if (myState == kfShift) myState = 0; + Event->Key.Code = k | myState; + return; + } + } + } + DEBUG(("Unknown key: %ld %s %d %d\n", key, keyname, etype, state)); + Event->What = evNone; +} + + +static TEvent LastMouseEvent = { evNone }; + +#define TM_DIFF(x,y) ((long)(((long)(x) < (long)(y)) ? ((long)(y) - (long)(x)) : ((long)(x) - (long)(y)))) + +void ConvertClickToEvent(int type, int xx, int yy, int button, int state, TEvent *Event, Time time) { + unsigned int myState = 0; + static unsigned long LastClickTime = 0; + static unsigned long LastClickCount = 0; + static unsigned long LastClick = 0; + unsigned long CurTime = time; + + if (type == MotionNotify) Event->What = evMouseMove; + else if (type == ButtonPress) Event->What = evMouseDown; + else Event->What = evMouseUp; + Event->Mouse.X = xx / cxChar; + Event->Mouse.Y = yy / cyChar; + if (Event->What == evMouseMove) + if (LastMouseX == Event->Mouse.X && + LastMouseY == Event->Mouse.Y) + { + Event->What = evNone; + return; + } + LastMouseX = Event->Mouse.X; + LastMouseY = Event->Mouse.Y; + Event->Mouse.Buttons = 0; + if (type == MotionNotify) { + if (state & Button1Mask) Event->Mouse.Buttons |= 1; + if (state & Button2Mask) Event->Mouse.Buttons |= 4; + if (state & Button3Mask) Event->Mouse.Buttons |= 2; + } else { + switch (button) { + case Button1: Event->Mouse.Buttons |= 1; break; + case Button2: Event->Mouse.Buttons |= 4; break; + case Button3: Event->Mouse.Buttons |= 2; break; + } + } + Event->Mouse.Count = 1; + if (state & ShiftMask) myState |= kfShift; + if (state & ControlMask) myState |= kfCtrl; + if (state & Mod1Mask) myState |= kfAlt; + if (state & Mod2Mask) myState |= kfAlt; + if (state & Mod3Mask) myState |= kfAlt; + if (state & Mod4Mask) myState |= kfAlt; + Event->Mouse.KeyMask = myState; + + if (Event->What == evMouseDown) { + if (LastClickCount) { + if (LastClick == Event->Mouse.Buttons) { + if (TM_DIFF(CurTime, LastClickTime) <= MouseMultiClick) { + Event->Mouse.Count = ++LastClickCount; + } else { + LastClickCount = 0; + } + } else { + LastClick = 0; + LastClickCount = 0; + LastClickTime = 0; + } + } + + LastClick = Event->Mouse.Buttons; + if (LastClickCount == 0) + LastClickCount = 1; + LastClickTime = CurTime; + } + /* if (Event->What == evMouseMove) { + LastClick = 0; + LastClickCount = 0; + LastClickTime = 0; + } + */ + DEBUG(("Mouse: %d %d %d\n", Event->What, Event->Mouse.X, Event->Mouse.Y)); + LastMouseEvent = *Event; +} + +void ProcessXEvents(XEvent *event, TEvent *Event, GViewPeer *Peer) { + XAnyEvent *anyEvent = (XAnyEvent *) event; + XExposeEvent *exposeEvent = (XExposeEvent *) event; + XButtonEvent *buttonEvent = (XButtonEvent *) event; + XKeyEvent *keyEvent = (XKeyEvent *) event; + XKeyEvent keyEvent1; + XConfigureEvent *configureEvent = (XConfigureEvent *) event; + XGraphicsExposeEvent *gexposeEvent = (XGraphicsExposeEvent *) event; + XMotionEvent *motionEvent = (XMotionEvent *) event; + KeySym key, key1; + int state; + char keyName[32]; + char keyName1[32]; + static int hasConfig = 0; + + Event->What = evNone; + Event->Msg.View = Peer->View; + + switch (event->type) { + case ButtonRelease: + case ButtonPress: + LastRelease = *buttonEvent; + ConvertClickToEvent(event->type, buttonEvent->x, buttonEvent->y, buttonEvent->button, buttonEvent->state, Event, motionEvent->time); + break; + case KeyPress: + case KeyRelease: + state = keyEvent->state; + + keyEvent1 = *keyEvent; + keyEvent1.state &= ~(ShiftMask | ControlMask | Mod1Mask | Mod2Mask | Mod3Mask | Mod4Mask); + + XLookupString(keyEvent, keyName, sizeof(keyName), &key, 0); + XLookupString(&keyEvent1, keyName1, sizeof(keyName1), &key1, 0); + //key1 = XLookupKeysym(keyEvent, 0); + ConvertKeyToEvent(key, key1, keyName, event->type, state, Event); + break; + case MotionNotify: + ConvertClickToEvent(event->type, motionEvent->x, motionEvent->y, 0, motionEvent->state, Event, motionEvent->time); + break; + } +} + +static void CloseWindow(Widget w, GFramePeer *frame, XEvent *event, Boolean *cont) { + if (event->type != ClientMessage || + ((XClientMessageEvent *)event)->data.l[0] != WM_DELETE_WINDOW) + { + return ; + } + NextEvent.What = evCommand; + NextEvent.Msg.Command = cmClose; + *cont = False; +} + +void MainCallback (Widget w, mItem *item, XtPointer callData) { + DEBUG(("Main: %d\n", item->Cmd)); + NextEvent.What = evCommand; + NextEvent.Msg.Command = item->Cmd; +} + +void PopupCallback (Widget w, mItem *item, XtPointer callData) { + DEBUG(("Popup: %d\n", item->Cmd)); + NextEvent.What = evCommand; + NextEvent.Msg.Command = item->Cmd; +} + +void MenuPopdownCb (Widget w, mItem *item, XtPointer callData) { + DEBUG(("Popdown: %d\n", item->Cmd)); + if (LPopupMenu != 0) { + XtDestroyWidget(XtParent(LPopupMenu)); + LPopupMenu = 0; + } +} + +void InputWindow(Widget w, GViewPeer *Peer, XEvent *event, Boolean *cont) { + DEBUG(("Input\n")); + if (!Peer->View->IsActive()) + Peer->View->Parent->SelectView(Peer->View); + NextEvent.Msg.View = Peer->View; + ProcessXEvents(event, &NextEvent, Peer); + *cont = False; +} + +static void VisibilityCb(Widget w, GViewPeer *peer, XEvent *event, Boolean *cont) { + if (event->type != VisibilityNotify) + return; + + peer->Visibility = event->xvisibility.state; + DEBUG(("Visibility %d\n", peer->Visibility)); + + /* + * When we do an XCopyArea(), and the window is partially obscured, we want + * to receive an event to tell us whether it worked or not. + */ + /*XSetGraphicsExposures(display, gui.text_gc, + gui.visibility != VisibilityUnobscured);*/ + *cont = True; +} + +void ConfigureWindow(Widget w, GViewPeer *Peer, XEvent *event, Boolean *cont) { + Dimension Xd, Yd; + int X, Y; + XConfigureEvent *confEvent = (XConfigureEvent *) event; + + DEBUG(("Configure\n")); + Xd = confEvent->width; + Yd = confEvent->height; + X = Xd; + Y = Yd; + DEBUG(("Resize %d, %d\n", X, Y)); + X /= cxChar; + Y /= cyChar; + DEBUG(("!! Resize %d, %d\n", X, Y)); + if (X > 0 && Y > 0) { + Peer->ConSetSize(X, Y); + NextEvent.What = evCommand; + NextEvent.Msg.Command = cmResize; + } + DEBUG(("!! resize done\n")); + *cont = True; +} + +void ExposeWindow(Widget w, GViewPeer *Peer, XmDrawingAreaCallbackStruct *Call) { + XExposeEvent *exposeEvent = (XExposeEvent *) Call->event; + + DEBUG(("Expose\n")); + // if (!XtIsManaged(w)) return + Peer->UpdateWindow(exposeEvent->x, + exposeEvent->y, + exposeEvent->width, + exposeEvent->height); + DEBUG(("! Expose done\n")); +} + + +void VertValueChanged(Widget w, GViewPeer *Peer, XmScrollBarCallbackStruct *Call) { + if (!Peer->View->IsActive()) + Peer->View->Parent->SelectView(Peer->View); + if (Peer->VertPos != Call->value) { + NextEvent.What = evCommand; + NextEvent.Msg.View = Peer->View; + NextEvent.Msg.Command = cmVScrollMove; + NextEvent.Msg.Param1 = Call->value; + DEBUG(("Vert: %d\n", Call->value)); + Peer->VertPos = Call->value; + } +} + +void HorzValueChanged(Widget w, GViewPeer *Peer, XmScrollBarCallbackStruct *Call) { + if (!Peer->View->IsActive()) + Peer->View->Parent->SelectView(Peer->View); + if (Call->value != Peer->HorzPos) { + NextEvent.What = evCommand; + NextEvent.Msg.View = Peer->View; + NextEvent.Msg.Command = cmHScrollMove; + NextEvent.Msg.Param1 = Call->value; + DEBUG(("Horz: %d\n", Call->value)); + Peer->HorzPos = Call->value; + } +} + +/////////////////////////////////////////////////////////////////////////// + +GViewPeer::GViewPeer(GView *view, int XSize, int YSize) { + + View = view; + Visibility = VisibilityFullyObscured; + + // wX = 0; + // wY = 0; + wW = XSize; + wH = YSize; + sbVtotal = 0; + sbVstart = 0; + sbVamount = 0; + sbHtotal = 0; + sbHstart = 0; + sbHamount = 0; + wState = 0; + cVisible = 1; + cStart = 0; // % + cEnd = 100; + wRefresh = 0; + ScreenBuffer = 0; + cX = -1; + cY = -1; + VertPos = HorzPos = -1; + + for (int jj = 0; jj < 256; jj++) + gc[jj] = 0; + + ScrollWin = XtVaCreateWidget("ScrollWin", + xmScrolledWindowWidgetClass, frames->Peer->PanedWin, + XmNmarginHeight, 0, + XmNmarginWidth, 0, + XmNspacing, 0, + 0); + + TextWin = XtVaCreateManagedWidget ("TextWin", + xmDrawingAreaWidgetClass, ScrollWin, + XmNmarginHeight, 0, + XmNmarginWidth, 0, + XmNhighlightThickness, 0, + XmNshadowThickness, 0, + XmNwidthInc, cxChar, + XmNheightInc, cyChar, + XmNwidth, cxChar * 80, + XmNheight, cyChar * 30, + 0); + + /* XSetWindowColormap(display, XtWindow(TextWin), colormap);*/ + + XtVaSetValues (ScrollWin, + XmNworkWindow, TextWin, + 0); + + SbVert = XtVaCreateManagedWidget("VScrollBar", + xmScrollBarWidgetClass, ScrollWin, + XmNmarginHeight, 0, + XmNmarginWidth, 0, + XmNwidth, 20, + 0); + + SbHorz = XtVaCreateManagedWidget("HScrollBar", + xmScrollBarWidgetClass, ScrollWin, + XmNmarginHeight, 0, + XmNmarginWidth, 0, + XmNorientation, XmHORIZONTAL, + NULL); + + XtVaSetValues(ScrollWin, + XmNhorizontalScrollBar, SbHorz, + XmNverticalScrollBar, SbVert, + 0); + + XtManageChild(ScrollWin); + + gcv.foreground = Colors[0].pixel; + gcv.background = Colors[0].pixel; + gcv.font = fontStruct->fid; + gc[0] = XtGetGC(TextWin, + GCForeground | GCBackground | GCFont, &gcv); + // GCattr = 0x07; + + + /* XtAddCallback(TextWin, XmNinputCallback, InputWindow, this);*/ + + XtAddEventHandler(TextWin, + KeyPressMask | KeyReleaseMask | + ButtonPressMask | ButtonReleaseMask | ButtonMotionMask, + False, InputWindow, this); + XtAddEventHandler(TextWin, + VisibilityChangeMask, + False, VisibilityCb, + this); + XtAddEventHandler(TextWin, + StructureNotifyMask, + False, ConfigureWindow, this); + //XtAddCallback(TextWin, XmNresizeCallback, ResizeWindow, this); + XtAddCallback(TextWin, XmNexposeCallback, ExposeWindow, this); + + XtAddCallback(SbHorz, XmNvalueChangedCallback, HorzValueChanged, this); + XtAddCallback(SbHorz, XmNdragCallback, HorzValueChanged, this); + XtAddCallback(SbHorz, XmNincrementCallback, HorzValueChanged, this); + XtAddCallback(SbHorz, XmNdecrementCallback, HorzValueChanged, this); + XtAddCallback(SbHorz, XmNpageIncrementCallback, HorzValueChanged, this); + XtAddCallback(SbHorz, XmNpageDecrementCallback, HorzValueChanged, this); + XtAddCallback(SbHorz, XmNtoTopCallback, HorzValueChanged, this); + XtAddCallback(SbHorz, XmNtoBottomCallback, HorzValueChanged, this); + + XtAddCallback(SbVert, XmNvalueChangedCallback, VertValueChanged, this); + XtAddCallback(SbVert, XmNdragCallback, VertValueChanged, this); + XtAddCallback(SbVert, XmNincrementCallback, VertValueChanged, this); + XtAddCallback(SbVert, XmNdecrementCallback, VertValueChanged, this); + XtAddCallback(SbVert, XmNpageIncrementCallback, VertValueChanged, this); + XtAddCallback(SbVert, XmNpageDecrementCallback, VertValueChanged, this); + XtAddCallback(SbVert, XmNtoTopCallback, VertValueChanged, this); + XtAddCallback(SbVert, XmNtoBottomCallback, VertValueChanged, this); + +} + +GViewPeer::~GViewPeer() { + XtDestroyWidget(ScrollWin); +} + +int GViewPeer::AllocBuffer() { + int i; + unsigned char *p; + + ScreenBuffer = (unsigned char *)malloc(2 * wW * wH); + if (ScreenBuffer == NULL) return -1; + for (i = 0, p = ScreenBuffer; i < wW * wH; i++) { + *p++ = 32; + *p++ = 0x07; + } + return 0; +} + +#define InRange(x,a,y) (((x) <= (a)) && ((a) < (y))) +#define CursorXYPos(x,y) (ScreenBuffer + ((x) + ((y) * wW)) * 2) + +void GViewPeer::DrawCursor(int Show) { + if (!(View && View->Parent)) + return ; + if (!(wState & sfFocus)) + Show = 0; + + if (Visibility == VisibilityFullyObscured) + return; + + if (cX >= wW || cY >= wW || + cX + 1 > wW || cY + 1 > wH) + { + //fprintf(stderr, "%d %d %d %d %d %d\n", ScreenCols, ScreenRows, X, Y, W, H); + return; + } + + DEBUG(("DrawCursor %d %d\n", cX, cY)); + // if (!XtIsManaged(TextWin)) return ; + + if (cVisible && cX >= 0 && cY >= 0) { + unsigned char *p = CursorXYPos(cX, cY), attr; + attr = p[1]; + /*if (Show) attr = ((((attr << 4) & 0xF0)) | (attr >> 4)) ^ 0x77;*/ + if (Show) attr = (attr ^ 0x77); + + if (gc[attr] == 0) { + gcv.foreground = Colors[attr & 0xF].pixel; + gcv.background = Colors[(attr >> 4) & 0xF].pixel; + gcv.font = fontStruct->fid; + gc[attr] = XtGetGC(TextWin, + GCForeground | GCBackground | GCFont, &gcv); + } + XDrawImageString(display, XtWindow(TextWin), gc[attr], + cX * cxChar, + fontStruct->max_bounds.ascent + cY * cyChar, + p, 1); + } +} + +int GViewPeer::ConPutBox(int X, int Y, int W, int H, PCell Cell) { + int i; + unsigned char temp[256], attr; + unsigned char *p, *ps, *c, *ops; + int len, x, l, ox, olen, skip; + + if (!(View && View->Parent && gc)) + return 1; + + if (Visibility == VisibilityFullyObscured) + return - 1; + + if (X >= wW || Y >= wH || + X + W > wW || Y + H > wH) + { + //fprintf(stderr, "%d %d %d %d %d %d\n", ScreenCols, ScreenRows, X, Y, W, H); + return -1; + } + + + DEBUG(("PutBox %d | %d %d %d %d | %d %d\n", wRefresh, X, Y, W, H, wW, wH)); + for (i = 0; i < H; i++) { + len = W; + p = CursorXYPos(X, Y + i); + ps = (unsigned char *) Cell; + x = X; + while (len > 0) { + if (!wRefresh) { + c = CursorXYPos(x, Y + i); + skip = 0; + ops = ps; + ox = x; + olen = len; + while ((len > 0) && (*(unsigned short *) c == *(unsigned short *)ps)) x++, len--, ps+=2, c+=2, skip++; + if (len <= 0) break; + if (skip <= 4) { + ps = ops; + x = ox; + len = olen; + } + } + p = ps; + l = 1; + temp[0] = *ps++; attr = *ps++; + while ((l < len) && ((unsigned char) (ps[1]) == attr)) { + temp[l++] = *ps++; + ps++; + } + + if (gc[attr] == 0) { + gcv.foreground = Colors[attr & 0xF].pixel; + gcv.background = Colors[(attr >> 4) & 0xF].pixel; + gcv.font = fontStruct->fid; + gc[attr] = XtGetGC(TextWin, + GCForeground | GCBackground | GCFont, &gcv); + } + + XDrawImageString(display, + XtWindow(TextWin), gc[attr], + x * cxChar, + fontStruct->max_bounds.ascent + (Y + i) * cyChar, + temp, l); + x += l; + len -= l; + } + p = CursorXYPos(X, Y + i); + memcpy(p, Cell, W * 2); + if (i + Y == cY) + DrawCursor(1); + Cell += W; + } + DEBUG(("done putbox\n")); + return 0; +} + +void GViewPeer::UpdateWindow(int xx, int yy, int ww, int hh) { + PCell p; + int i; + ww /= cxChar; ww += 2; + hh /= cyChar; hh += 2; + xx /= cxChar; + yy /= cyChar; + if (xx + ww > wW) ww = wW - xx; + if (yy + hh > wH) hh = wH - yy; + wRefresh = 1; + p = (PCell) CursorXYPos(xx, yy); + for (i = 0; i < hh; i++) { + ConPutBox(xx, yy + i, ww, 1, p); + p += wW; + } + XFlush(display); + wRefresh = 0; +} + +int GViewPeer::ConGetBox(int X, int Y, int W, int H, PCell Cell) { + int i; + + for (i = 0; i < H; i++) { + memcpy(Cell, CursorXYPos(X, Y + i), 2 * W); + Cell += W; + } + return 0; +} + +int GViewPeer::ConPutLine(int X, int Y, int W, int H, PCell Cell) { + int i; + + for (i = 0; i < H; i++) { + if (ConPutBox(X, Y + i, W, 1, Cell) != 0) return -1; + } + return 0; +} + +int GViewPeer::ConSetBox(int X, int Y, int W, int H, TCell Cell) { + TDrawBuffer B; + int i; + + for (i = 0; i < W; i++) B[i] = Cell; + ConPutLine(X, Y, W, H, B); + return 0; +} + +int GViewPeer::ConScroll(int Way, int X, int Y, int W, int H, TAttr Fill, int Count) { + TCell Cell; + int l; + + MoveCh(&Cell, ' ', Fill, 1); + DrawCursor(0); + if (Way == csUp) { + XCopyArea(display, XtWindow(TextWin), XtWindow(TextWin), gc[0], + X * cxChar, + (Y + Count) * cyChar, + W * cxChar, + (H - Count) * cyChar, + X * cxChar, + Y * cyChar + ); + for (l = 0; l < H - Count; l++) { + memcpy(CursorXYPos(X, Y + l), CursorXYPos(X, Y + l + Count), 2 * W); + } + if (ConSetBox(X, Y + H - Count, W, Count, Cell) == -1) return -1; + } else if (Way == csDown) { + XCopyArea(display, XtWindow(TextWin), XtWindow(TextWin), gc[0], + X * cxChar, + Y * cyChar, + W * cxChar, + (H - Count) * cyChar, + X * cxChar, + (Y + Count)* cyChar + ); + for (l = H - 1; l >= Count; l--) { + memcpy(CursorXYPos(X, Y + l), CursorXYPos(X, Y + l - Count), 2 * W); + } + if (ConSetBox(X, Y, W, Count, Cell) == -1) return -1; + } + DrawCursor(1); + return 0; +} + +int GViewPeer::ConSetSize(int X, int Y) { + unsigned char *NewBuffer; + unsigned char *p; + int i; + unsigned int MX, MY; + + p = NewBuffer = (unsigned char *) malloc(X * Y * 2); + if (NewBuffer == NULL) return -1; + for (i = 0; i < X * Y; i++) { + *p++ = ' '; + *p++ = 0x07; + } + if (ScreenBuffer) { + MX = wW; if (X < MX) MX = X; + MY = wH; if (Y < MY) MY = Y; + if (X < MX) MX = X; + p = NewBuffer; + for (i = 0; i < MY; i++) { + memcpy(p, CursorXYPos(0, i), MX * 2); + p += X * 2; + } + free(ScreenBuffer); + } + ScreenBuffer = NewBuffer; + wW = X; + wH = Y; + wRefresh = 1; + View->Resize(wW, wH); + ConPutBox(0, 0, wW, wH, (PCell) ScreenBuffer); + wRefresh = 0; + // if (Refresh == 0) + // XResizeWindow(display, win, ScreenCols * cxChar, ScreenRows * cyChar); + return 1; +} + +int GViewPeer::ConQuerySize(int *X, int *Y) { + if (X) *X = wW; + if (Y) *Y = wH; + return 1; +} + +int GViewPeer::ConSetCursorPos(int X, int Y) { + if (X < 0) X = 0; + if (X >= wW) X = wW - 1; + if (Y < 0) Y = 0; + if (Y >= wH) Y = wH - 1; + DrawCursor(0); + cX = X; + cY = Y; + DrawCursor(1); + return 1; +} + +int GViewPeer::ConQueryCursorPos(int *X, int *Y) { + if (X) *X = cX; + if (Y) *Y = cY; + return 1; +} + +int GViewPeer::ConShowCursor() { + cVisible = 1; + // DrawCursor(1); + return 1; +} + +int GViewPeer::ConHideCursor() { + cVisible = 0; + // DrawCursor(0); + return 1; +} + +int GViewPeer::ConCursorVisible() { + return cVisible; +} + +int GViewPeer::ConSetCursorSize(int Start, int End) { + cStart = Start; + cEnd = End; + if (wState & sfFocus) + return 1; //PMSetCursorSize(Start, End); + else + return 1; +} + +int GViewPeer::ExpandHeight(int DeltaY) { + return 0; +} + +int GViewPeer::QuerySbVPos() { + return sbVstart; +} + +int GViewPeer::SetSbVPos(int Start, int Amount, int Total) { + if (sbVstart != Start || + sbVamount != Amount || + sbVtotal != Total) + { + sbVstart = Start; + sbVamount = Amount; + sbVtotal = Total; + + if (View->Parent == 0) + return 0; + if (Amount < 1 || Start + Amount > Total) { + XtVaSetValues(SbVert, + XmNmaximum, 1, + XmNminimum, 0, + XmNpageIncrement, 1, + XmNsliderSize, 1, + XmNvalue, 0, + 0); + } else { + XtVaSetValues(SbVert, + XmNmaximum, Total, + XmNminimum, 0, + XmNpageIncrement, ((Amount > 1) ? Amount : 1), + XmNsliderSize, Amount, + XmNvalue, Start, + 0); + } + } + return 1; +} + +int GViewPeer::SetSbHPos(int Start, int Amount, int Total) { + if (sbHstart != Start || + sbHamount != Amount || + sbHtotal != Total) + { + sbHstart = Start; + sbHamount = Amount; + sbHtotal = Total; + + if (View->Parent == 0) + return 0; + + if (Amount < 1 || Start + Amount > Total) { + XtVaSetValues(SbHorz, + XmNmaximum, 1, + XmNminimum, 0, + XmNpageIncrement, 1, + XmNsliderSize, 1, + XmNvalue, 0, + 0); + } else { + XtVaSetValues(SbHorz, + XmNmaximum, Total, + XmNminimum, 0, + XmNpageIncrement, ((Amount > 1) ? Amount : 1), + XmNsliderSize, Amount, + XmNvalue, Start, + 0); + } + } + return 1; +} + +int GViewPeer::UpdateCursor() { + ConSetCursorPos(cX, cY); + ConSetCursorSize(cStart, cEnd); + if (cVisible) + ConShowCursor(); + else + ConHideCursor(); + return 1; +} + +int GViewPeer::PMShowCursor() { + // if (wState & sfFocus) + // WinShowCursor(hwndView, TRUE); + return 1; +} + +int GViewPeer::PMHideCursor() { + // if (wState & sfFocus) + // WinShowCursor(hwndView, FALSE); + return 1; +} + +int GViewPeer::PMSetCursorPos() { + // if (wState & sfFocus) { + // WinDestroyCursor(hwndView); + // WinCreateCursor(hwndView, + // cxChar * cX, cyChar * (wH - cY - 1), cxChar, 2, + // CURSOR_TYPE, + // NULL); + // WinShowCursor(hwndView, TRUE); + // } + return 1; +} + +/////////////////////////////////////////////////////////////////////////// + +GView::GView(GFrame *parent, int XSize, int YSize) { + Parent = parent; + Prev = Next = 0; + Peer = new GViewPeer(this, XSize, YSize); + if (Parent) + Parent->AddView(this); +} + +GView::~GView() { + if (Parent) + Parent->RemoveView(this); + if (Peer) + delete Peer; +} + +int GView::ConClear() { + int W, H; + TDrawBuffer B; + + ConQuerySize(&W, &H); + MoveChar(B, 0, W, ' ', 0x07, 1); + ConSetBox(0, 0, W, H, B[0]); + return 1; +} + +int GView::ConPutBox(int X, int Y, int W, int H, PCell Cell) { + return Peer->ConPutBox(X, Y, W, H, Cell); +} + +int GView::ConGetBox(int X, int Y, int W, int H, PCell Cell) { + return Peer->ConGetBox(X, Y, W, H, Cell); +} + +int GView::ConPutLine(int X, int Y, int W, int H, PCell Cell) { + return Peer->ConPutLine(X, Y, W, H, Cell); +} + +int GView::ConSetBox(int X, int Y, int W, int H, TCell Cell) { + return Peer->ConSetBox(X, Y, W, H, Cell); +} + +int GView::ConScroll(int Way, int X, int Y, int W, int H, TAttr Fill, int Count) { + return Peer->ConScroll(Way, X, Y, W, H, Fill, Count); +} + +int GView::ConSetSize(int X, int Y) { + if (Peer->ConSetSize(X, Y)) ; + // Resize(X, Y); + else + return 0; + return 1; +} + +int GView::ConQuerySize(int *X, int *Y) { + return Peer->ConQuerySize(X, Y); +} + +int GView::ConSetCursorPos(int X, int Y) { + return Peer->ConSetCursorPos(X, Y); +} + +int GView::ConQueryCursorPos(int *X, int *Y) { + return Peer->ConQueryCursorPos(X, Y); +} + +int GView::ConShowCursor() { + return Peer->ConShowCursor(); +} + +int GView::ConHideCursor() { + return Peer->ConHideCursor(); +} + +int GView::ConCursorVisible() { + return Peer->ConCursorVisible(); +} + +int GView::ConSetCursorSize(int Start, int End) { + return Peer->ConSetCursorSize(Start, End); +} + +int GView::QuerySbVPos() { + return Peer->QuerySbVPos(); +} + +int GView::SetSbVPos(int Start, int Amount, int Total) { + return Peer->SetSbVPos(Start, Amount, Total); +} + +int GView::SetSbHPos(int Start, int Amount, int Total) { + return Peer->SetSbHPos(Start, Amount, Total); +} + +int GView::ExpandHeight(int DeltaY) { + return Peer->ExpandHeight(DeltaY); +} + +void GView::Update() { +} + +void GView::Repaint() { +} + +void GView::HandleEvent(TEvent &Event) { +} + +void GView::Resize(int width, int height) { + Repaint(); +} + +void GView::EndExec(int NewResult) { + Result = NewResult; +} + +int GView::Execute() { + int SaveRc = Result; + int NewResult; + + Result = -2; + while (Result == -2 && frames != 0) + gui->ProcessEvent(); + NewResult = Result; + Result = SaveRc; + return NewResult; +} + +int GView::IsActive() { + return (Parent->Active == this); +} + +void GView::Activate(int gotfocus) { + if (gotfocus) { + Peer->wState |= sfFocus; + Peer->UpdateCursor(); + } else { + Peer->wState &= ~sfFocus; + } + Repaint(); +} + +int GView::CaptureMouse(int grab) { + if (MouseCapture == 0) { + if (grab) + MouseCapture = this; + else + return 0; + } else { + if (grab || MouseCapture != this) + return 0; + else + MouseCapture = 0; + } + return 1; +} + +/////////////////////////////////////////////////////////////////////////// + +GFramePeer::GFramePeer(GFrame *frame, int Width, int Height) { + ShellWin = XtCreatePopupShell("fte", topLevelShellWidgetClass, + TopLevel, NULL, 0); + + XtVaSetValues(ShellWin, + XmNwidthInc, cxChar, + XmNheightInc, cyChar, + NULL); + + MainWin = XtCreateManagedWidget("Widget", xmMainWindowWidgetClass, + ShellWin, NULL, 0); + + PanedWin = XtVaCreateManagedWidget("pane", + xmPanedWindowWidgetClass, MainWin, + XmNmarginHeight, 0, + XmNmarginWidth, 0, + 0 ); + + XtVaSetValues (MainWin, + XmNworkWindow, PanedWin, + 0); + + if (Width != -1 && Height != -1) + ConSetSize(Width, Height); +} + +GFramePeer::~GFramePeer() { +} + +int GFramePeer::ConSetSize(int X, int Y) { + //return ::ConSetSize(X, Y); + return 0; +} + +int GFramePeer::ConQuerySize(int *X, int *Y) { + // ::ConQuerySize(&fW, &fH); + // if (X) *X = fW; + // if (Y) *Y = fH; + return 1; +} + +//int GFrame::ConQuerySize(int *X, int *Y) { +// ::ConQuerySize(X, Y); +// if (ShowVScroll) +// --*X; +//} + +int GFramePeer::ConSetTitle(char *Title, char *STitle) { + XSetStandardProperties(display, XtWindow(ShellWin), Title, STitle, 0, NULL, 0, NULL); + return 1; +} + +int GFramePeer::ConGetTitle(char *Title, int MaxLen, char *STitle, int SMaxLen) { + *Title = 0; + *STitle = 0; + return 1; +} + +void GFramePeer::MapFrame() { + //Parent->UpdateMenu(); + XtPopup(ShellWin, XtGrabNone); + XSetWMProtocols(display, XtWindow(ShellWin), &WM_DELETE_WINDOW, 1); + XtInsertEventHandler(ShellWin, NoEventMask, True, CloseWindow, NULL, XtListHead); +} + +/////////////////////////////////////////////////////////////////////////// + +GFrame::GFrame(int XSize, int YSize) { + Menu = 0; + if (frames == 0) { + frames = Prev = Next = this; + } else { + Next = frames->Next; + Prev = frames; + frames->Next->Prev = this; + frames->Next = this; + frames = this; + } + Top = Active = 0; + Peer = new GFramePeer(this, XSize, YSize); +} + +GFrame::~GFrame() { + if (Peer) { + delete Peer; + Peer = 0; + } + if (Next == this) { + frames = 0; + // DEBUG(("No more frames\x7\x7\n")); + } else { + Next->Prev = Prev; + Prev->Next = Next; + frames = Next; + } + Next = Prev = 0; +} + +int GFrame::ConSetTitle(char *Title, char *STitle) { + return Peer->ConSetTitle(Title, STitle); +} + +int GFrame::ConGetTitle(char *Title, int MaxLen, char *STitle, int SMaxLen) { + return Peer->ConGetTitle(Title, MaxLen, STitle, SMaxLen); +} + +int GFrame::ConSetSize(int X, int Y) { + return Peer->ConSetSize(X, Y); +} + +int GFrame::ConQuerySize(int *X, int *Y) { + return Peer->ConQuerySize(X, Y); +} + +int GFrame::ConSplitView(GView *view, GView *newview) { + int dmy; + + newview->Parent = this; + // newview->Peer->wX = 0; + ConQuerySize(&newview->Peer->wW, &dmy); + // newview->Peer->wY = view->Peer->wY + view->Peer->wH / 2; + // newview->Peer->wH = view->Peer->wH - view->Peer->wH / 2; + // view->Peer->wH /= 2; + InsertView(view, newview); + view->ConSetSize(view->Peer->wW, view->Peer->wH); + newview->ConSetSize(newview->Peer->wW, newview->Peer->wH); + return 0; +} + +int GFrame::ConCloseView(GView *view) { + return 0; +} + +int GFrame::ConResizeView(GView *view, int DeltaY) { + return 0; +} + +int GFrame::AddView(GView *view) { + if (Top != 0) { + return ConSplitView(Top, view); + } else { + // int W, H; + + view->Parent = this; + view->Prev = view->Next = 0; + + // view->Peer->wX = 0; + // view->Peer->wY = 0; + // ConQuerySize(&W, &H); + // view->ConSetSize(W, H); + InsertView(Top, view); + return 0; + } +} + +void GFrame::Update() { + GView *v = Active; + + UpdateMenu(); + while (v) { + v->Update(); + v = v->Next; + if (v == Active) + break; + } +} + +void GFrame::UpdateMenu() { +} + +void GFrame::Repaint() { + GView *v = Active; + + while (v) { + v->Repaint(); + v = v->Next; + if (v == Active) + break; + } +} + +void GFrame::InsertView(GView *Prev, GView *view) { + if (!view) return ; + if (Prev) { + view->Prev = Prev; + view->Next = Prev->Next; + Prev->Next = view; + view->Next->Prev = view; + } else { + view->Prev = view->Next = view; + Top = view; + } + if (Active == 0) { + Active = view; + Active->Activate(1); + } +} + +void GFrame::RemoveView(GView *view) { + if (!view) return ; + + if (Active == view) + Active->Activate(0); + if (view->Next == view) { + Top = Active = 0; + delete this; + } else { + view->Next->Prev = view->Prev; + view->Prev->Next = view->Next; + + // if (Top == view) { + // Top = view->Next; + // Top->Peer->wY -= view->Peer->wH; + // Top->ConSetSize(Top->Peer->wW, Top->Peer->wH + view->Peer->wH); + // } else { + // view->Prev->ConSetSize(view->Prev->Peer->wW, + // view->Prev->Peer->wH + view->Peer->wH); + // } + + if (Active == view) { + Active = view->Prev; + Active->Activate(1); + } + } +} + +void GFrame::SelectNext(int back) { + GView *c = Active; + + if (c == 0 && Top == 0) + return; + else if (c == 0) + c = Active = Top; + else + if (back) { + Active = Active->Prev; + } else { + Active = Active->Next; + } + if (c != Active) { + c->Activate(0); + Active->Activate(1); + } + if (Active) + XtSetKeyboardFocus(Peer->PanedWin, Active->Peer->TextWin); +} + +int GFrame::SelectView(GView *view) { + if (Top == 0) + return 0; + + if (FocusCapture != 0 || MouseCapture != 0) + return 0; + + if (Active) + Active->Activate(0); + Active = view; + if (Active) + Active->Activate(1); + if (Active) + XtSetKeyboardFocus(Peer->PanedWin, Active->Peer->TextWin); + return 1; +} + +void GFrame::Resize(int width, int height) { + if (!Top) + return; + + if (width < 8 || height < 2) + return; + + if (Top == Top->Next) { + Top->ConSetSize(width, height); + } else { + } +} + +Widget CreateMotifMenu(Widget parent, int menu, int main, XtCallbackProc MenuProc) { + Widget hmenu; + int i; + char s[256]; + char *p; + Widget item; + + if (main == 1) { + hmenu = XmCreateMenuBar(parent, "menu", NULL, 0); + } else if (main == 2) { + hmenu = XmCreatePopupMenu(parent, "submenu", + NULL, 0); + // XtCreateManagedWidget ( "Title", xmLabelWidgetClass, hmenu, + // NULL, 0 ); + + // XtCreateManagedWidget ( "separator", xmSeparatorWidgetClass, + // hmenu, NULL, 0 ); + } else { + hmenu = XmCreatePulldownMenu(parent, "submenu", + NULL, 0); + } + + for (i = 0; i < Menus[menu].Count; i++) { + if (Menus[menu].Items[i].Name) { + char *mn = 0; + + strcpy(s, Menus[menu].Items[i].Name); + p = strchr(s, '&'); + if (p) { + strcpy(p, p + 1); + mn = p; + } + p = strchr(s, '\t'); + if (p) { + *p = 0; + p++; + } + + if (Menus[menu].Items[i].SubMenu != -1) { + item = XtVaCreateManagedWidget(s, + xmCascadeButtonWidgetClass, + hmenu, + XmNsubMenuId, + CreateMotifMenu(hmenu, + Menus[menu].Items[i].SubMenu, + 0, MenuProc), + NULL ); + } else { + item = XtVaCreateManagedWidget(s, + xmPushButtonWidgetClass, hmenu, + 0); + XtAddCallback(item, XmNactivateCallback, + MenuProc, &(Menus[menu].Items[i])); + } + + if (p) + XtVaSetValues(item, + XmNacceleratorText, + XmStringCreate(p, XmSTRING_DEFAULT_CHARSET), + 0); + if (mn) + XtVaSetValues(item, + XmNmnemonic, + KeySym(*mn), + 0); + } else { + item = XtVaCreateManagedWidget("separator", + xmSeparatorWidgetClass, + hmenu, + 0); + //XmCreateSeparator(parent, "xx", 0, 0); + } + // item.id = Menus[menu].Items[i].Cmd & 0xFFFF; // ? + } + return hmenu; +} + +Widget CreateMotifMainMenu(Widget parent, char *Name) { + int id = GetMenuId(Name); + + return CreateMotifMenu(parent, id, 1, MainCallback); +} + +int GFrame::SetMenu(const char *Name) { + if (Menu) free(Menu); + Menu = strdup(Name); + + Peer->MenuBar = CreateMotifMainMenu(Peer->MainWin, Name); + XtManageChild (Peer->MenuBar); + XtVaSetValues (Peer->MainWin, + XmNmenuBar, Peer->MenuBar, + 0); + + return 1; +} + +int GFrame::ExecMainMenu(char Sub) { + return 0; +} + +int GFrame::PopupMenu(const char *Name) { + int id = GetMenuId(Name); + + LPopupMenu = CreateMotifMenu(Peer->MainWin, id, 2, (XtCallbackProc)PopupCallback); + XtAddCallback(XtParent(LPopupMenu), XmNpopdownCallback, MenuPopdownCb, 0); + XmMenuPosition (LPopupMenu, (XButtonEvent *)&LastRelease); + XtManageChild (LPopupMenu); + return 1; +} + +// GUI + + +GUI::GUI(int &argc, char **argv, int XSize, int YSize) { + + char *fs = getenv("VIOFONT"); + if (fs == 0 && WindowFont[0] != 0) + fs = WindowFont; + + TopLevel = XtVaAppInitialize(&AppContext, "TopLevel", NULL, 0, + &argc, argv, NULL, + XmNmappedWhenManaged, FALSE, + NULL); + + if (TopLevel == 0) + return ; + + display = XtDisplay(TopLevel); + //XSynchronize(display, True); + if (display == NULL) + return; + + root = DefaultRootWindow(display); + screen = DefaultScreen(display); + colormap = DefaultColormap(display, screen); + + InitXColors(); + + fontStruct = NULL; + if (fs) + fontStruct = XLoadQueryFont(display, fs); + else { +#ifdef HPUX + fontStruct = XLoadQueryFont(display, "8x13"); +#endif +#ifdef AIX + fontStruct = XLoadQueryFont(display, "8x13"); +#endif +#ifdef LINUX + fontStruct = XLoadQueryFont(display, "8x13"); +#endif +#ifdef IRIX + fontStruct = XLoadQueryFont(display, "8x13"); +#endif + } + if (fontStruct == NULL) + fontStruct = XLoadQueryFont(display, "fixed"); + if (fontStruct == NULL) + return; + cxChar = fontStruct->max_bounds.width; + cyChar = fontStruct->max_bounds.ascent + fontStruct->max_bounds.descent; + XtRealizeWidget(TopLevel); + + WM_DELETE_WINDOW = XInternAtom(display, "WM_DELETE_WINDOW", False); + + gui = this; +} + +GUI::~GUI() { + gui = 0; +} + +int GUI::ConGrabEvents(TEventMask EventMask) { + return 0; +} + +void GUI::DispatchEvent(GFrame *frame, GView *view, TEvent &Event) { + if (Event.What != evNone) { + if (view) + view->HandleEvent(Event); + } +} + +int GUI::ConSuspend(void) { return 0; } + +int GUI::ConContinue(void) { return 0; } + +int GUI::ConGetEvent(TEventMask EventMask, TEvent *Event, int WaitTime, int Delete, GView **view) { + //return ::ConGetEvent(EventMask, Event, WaitTime, Delete, view); + assert(1 == 0); + return 0; +} + +int GUI::ConPutEvent(TEvent Event) { + EventBuf = Event; + return 0; +} + +int GUI::ConFlush(void) { + return 0; +} + +void GUI::ProcessEvent() { + static int need_update = 1; + + if (need_update && XtAppPending(AppContext) == 0 ) { + frames->Update(); + need_update = 0; + } + XtAppProcessEvent(AppContext, XtIMAll); + if (NextEvent.What != evNone) { + DispatchEvent(frames, NextEvent.Msg.View, NextEvent); + NextEvent.What = evNone; + need_update = 1; + } +} + +int GUI::Run() { + frames->Peer->MapFrame(); + + //XtAppMainLoop(AppContext); + while (frames != 0) + ProcessEvent(); + + return 0; +} + +int GUI::ShowEntryScreen() { + return 1; +} + +int GUI::RunProgram(int mode, char *Command) { + char Cmd[1024]; + + char* xterm = getenv("TERM"); + if (NULL == xterm || 0 == *xterm) + xterm = "xterm"; + + strcpy(Cmd, xterm); + + if (*Command == 0) // empty string = shell + strcat(Cmd, " -ls &"); + else { + strcat(Cmd, " -e "); + // buffer overflow problem: -2 for possible async. + strncat(Cmd, Command, sizeof(Cmd) - strlen(Cmd) - 2); + Cmd[sizeof(Cmd) - 3] = 0; + if (mode == RUN_ASYNC) + strcat(Cmd, " &"); + } + rc = system(Cmd); + return rc; +} + +void PipeCallback(GPipe *pipe, int *source, XtInputId *input) { + if (pipe && pipe->notify && *source == pipe->fd) { + NextEvent.What = evNotify; + NextEvent.Msg.View = frames->Active; + NextEvent.Msg.Model = pipe->notify; + NextEvent.Msg.Command = cmPipeRead; + NextEvent.Msg.Param1 = pipe->id; + pipe->stopped = 0; + } + //fprintf(stderr, "Pipe %d\n", *source); +} + +int GUI::OpenPipe(char *Command, EModel *notify) { + int i; + + for (i = 0; i < MAX_PIPES; i++) { + if (Pipes[i].used == 0) { + int pfd[2]; + + Pipes[i].id = i; + Pipes[i].notify = notify; + Pipes[i].stopped = 1; + + if (pipe((int *)pfd) == -1) + return -1; + + switch (Pipes[i].pid = fork()) { + case -1: /* fail */ + return -1; + case 0: /* child */ + close(pfd[0]); + close(0); + dup2(pfd[1], 1); + dup2(pfd[1], 2); + exit(system(Command)); + default: + close(pfd[1]); + fcntl(pfd[0], F_SETFL, O_NONBLOCK); + Pipes[i].fd = pfd[0]; + } + Pipes[i].input = + XtAppAddInput(AppContext, Pipes[i].fd, XtInputReadMask, PipeCallback, &Pipes[i]); + Pipes[i].used = 1; + //fprintf(stderr, "Pipe Open: %d\n", i); + return i; + } + } + return -1; +} + +int GUI::SetPipeView(int id, EModel *notify) { + if (id < 0 || id > MAX_PIPES) + return -1; + if (Pipes[id].used == 0) + return -1; + //fprintf(stderr, "Pipe View: %d %08X\n", id, notify); + Pipes[id].notify = notify; + if (notify != Pipes[id].notify) + if (notify) { + Pipes[id].input = + XtAppAddInput(AppContext, Pipes[id].fd, XtInputReadMask, PipeCallback, &Pipes[id]); + } else { + if (Pipes[id].input != 0) { + XtRemoveInput(Pipes[id].input); + Pipes[id].input = 0; + } + } + return 0; +} + +int GUI::ReadPipe(int id, void *buffer, int len) { + int rc; + + if (id < 0 || id > MAX_PIPES) + return -1; + if (Pipes[id].used == 0) + return -1; + //fprintf(stderr, "Pipe Read: Get %d %d\n", id, len); + + rc = read(Pipes[id].fd, buffer, len); + //fprintf(stderr, "Pipe Read: Got %d %d\n", id, len); + if (rc == 0) { + if (Pipes[id].input != 0) { + XtRemoveInput(Pipes[id].input); + Pipes[id].input = 0; + } + close(Pipes[id].fd); + return -1; + } + if (rc == -1) { + Pipes[id].stopped = 1; + return 0; + } + return rc; +} + +int GUI::ClosePipe(int id) { + int status; + + if (id < 0 || id > MAX_PIPES) + return -1; + if (Pipes[id].used == 0) + return -1; + waitpid(Pipes[id].pid, &status, 0); + //fprintf(stderr, "Pipe Close: %d\n", id); + Pipes[id].used = 0; + return WEXITSTATUS(status); +} + +int GetXSelection(int *len, char **data) { + *data = XFetchBytes(display, len); + if (*data == 0) + return -1; + else + return 0; +} + +int SetXSelection(int len, char *data) { + XStoreBytes(display, data, len); + XSetSelectionOwner (display, XA_PRIMARY, None, CurrentTime); + return 1; +} + +/* + static void SetColor(int i) { + int j, k, z; + j = i & 7; + k = 65535 - 20480; + z = (i > 7) ? (20480) : 0; + Colors[i].blue = k * (j & 1) + z; + Colors[i].green = k * ((j & 2)?1:0) + z; + Colors[i].red = k * ((j & 4)?1:0) + z; + Colors[i].flags = DoRed | DoGreen | DoBlue; + } + + static int InitXColors() { + int i; + + for (i = 0; i < 16; i++) { + SetColor(i); + if (XAllocColor(display, colormap, &Colors[i]) == 0) { + colormap = XCreateColormap(display, win, DefaultVisual(display, screen), AllocNone); + for (i = 0; i < 16; i++) { + SetColor(i); + XAllocColor(display, colormap, &Colors[i]); + } + XSetWindowColormap(display, win, colormap); + return 0; + } + } + return 0; + } + static int InitXGCs() { + int i; + XGCValues gcv; + + for (i = 0; i < 256; i++) { + gcv.foreground = Colors[i % 16].pixel; + gcv.background = Colors[(i / 16)].pixel; + gcv.font = fontStruct->fid; + GCs[i] = XCreateGC(display, win, GCForeground | GCBackground | GCFont, &gcv); + } + return 0; + } + */ + +void DieError(int rc, const char *msg, ...) { + va_list ap; + + va_start(ap, msg); + vfprintf(stderr, msg, ap); + va_end(ap); + exit(rc); +} + +char ConGetDrawChar(int index) { + static char tab[] = "\x0D\x0C\x0E\x0B\x12\x19____+>\x1F\x01\x12 "; + + assert(index >= 0 && index < strlen(tab)); + + return tab[index]; +} diff --git a/src/g_nodlg.cpp b/src/g_nodlg.cpp new file mode 100644 index 0000000..4694836 --- /dev/null +++ b/src/g_nodlg.cpp @@ -0,0 +1,32 @@ +// used in text mode versions, should never be called (just for linking) + +#include +#include +#include "console.h" +#include "gui.h" + +int DLGGetFile(GView *v, const char *Prompt, unsigned int BufLen, char *FileName, int Flags) { + assert(1==0); + return 0; +} + +int DLGPickChoice(GView *v, const char *ATitle, int NSel, va_list ap, int Flags) { + assert(1==0); + return 0; +} + +int DLGGetFind(GView *View, SearchReplaceOptions &sr) { + assert(1==0); + return 0; +} + +int DLGGetFindReplace(GView *View, SearchReplaceOptions &sr) { + assert(1==0); + return 0; +} + +int DLGGetStr(GView *View, const char *Prompt, unsigned int BufLen, char *Str, int HistId, int Flags) { + assert(1 == 0); + return 0; +} + diff --git a/src/g_pm.cpp b/src/g_pm.cpp new file mode 100644 index 0000000..6668ff1 --- /dev/null +++ b/src/g_pm.cpp @@ -0,0 +1,3891 @@ +/* g_pm.cpp + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +/* + * here's how it works: + * there's one visible and one object window per view + * events are forwarded from the visible on to object window and pulled + * into the editor from the worker thread (there's only one, FTE + * editor core is single-threaded). + * SIQ is never blocked. + * the only problem is that window doesn't repaint correctly after resize, + * until the worker thread finishes processing, but we can't really + * do anything with this as the editor core is not thread-safe. + */ + +#define INCL_WIN +#define INCL_GPI +#define INCL_VIO +#define INCL_AVIO +#define INCL_DOS +#define INCL_DOSERRORS + +#include +#include +#include +#include +#include +#include +#include +#include +#include "ftever.h" +#include "sysdep.h" +#include "feature.h" +#include "console.h" +#include "gui.h" +#include "c_history.h" +#include "c_commands.h" +#include "c_config.h" +#include "c_mode.h" +#include "c_color.h" +#include "s_files.h" +#include "log.h" + +#define PM_STACK_SIZE (96 * 1024) + +#define UWM_NOTIFY (WM_USER + 1) +#define UWM_DESTROY (WM_USER + 2) +#define UWM_DESTROYHWND (WM_USER + 3) +#define UWM_DROPPEDFILE (WM_USER + 4) +#define UWM_FILEDIALOG (WM_USER + 5) +#define UWM_DLGBOX (WM_USER + 6) +#define UWM_PROCESSDLG (WM_USER + 7) +#define UWM_CHOICE (WM_USER + 8) +#define UWM_CREATECHILD (WM_USER + 9) +#define UWM_CREATEWORKER (WM_USER + 10) +#define UWM_CREATEFRAME (WM_USER + 11) +#define UWM_CREATEMAINMENU (WM_USER + 12) +#define UWM_CREATEPOPUPMENU (WM_USER + 13) + +#define CURSOR_TYPE (CURSOR_FLASH | CURSOR_SOLID) + +//#define SIZER_HEIGHT 4 + +#define FID_MTOOLBAR 10001 + +#define MAXXSIZE 160 +#define MAXYSIZE 96 + +#define MAX_PIPES 4 +#define PIPE_BUFLEN 4096 + +typedef struct { + int used; + int id; + int reading, stopped; + TID tid; + HMTX Access; + HEV ResumeRead; + char *buffer; + int buflen; + int bufused; + int bufpos; + EModel *notify; + char *Command; + int RetCode; + int DoTerm; +} GPipe; + +static GPipe Pipes[MAX_PIPES] = { + { 0 }, { 0 }, { 0 }, { 0 } +}; + +#define sfFocus 1 + +typedef struct _PMPTR { // for passing pointers to winprocs + USHORT len; + void *p; +} PMPTR; + +class GViewPeer; + +struct PMData { + GViewPeer *Peer; + HVPS hvps; + HPS hps; + SHORT cxChar; + SHORT cyChar; + HWND hwndWorker; +}; + +class GViewPeer { +public: + GView *View; +// int wX, wY; + int wW, wH, wState; + int cX, cY, cVisible, cStart, cEnd; + int sbVstart, sbVamount, sbVtotal; + int sbHstart, sbHamount, sbHtotal; + + HWND hwndView; + HWND hwndVscroll, hwndHscroll; + HWND hwndWorker; + PMData *pmData; + int OldMouseX, OldMouseY; + + GViewPeer(GView *view, int XSize, int YSize); + ~GViewPeer(); + + int ConPutBox(int X, int Y, int W, int H, PCell Cell); + int ConGetBox(int X, int Y, int W, int H, PCell Cell); + int ConPutLine(int X, int Y, int W, int H, PCell Cell); + int ConSetBox(int X, int Y, int W, int H, TCell Cell); + int ConScroll(int Way, int X, int Y, int W, int H, TAttr Fill, int Count); + + int ConSetSize(int X, int Y); + int ConQuerySize(int *X, int *Y); + + int ConSetCursorPos(int X, int Y); + int ConQueryCursorPos(int *X, int *Y); + int ConShowCursor(); + int ConHideCursor(); + int ConCursorVisible(); + int ConSetCursorSize(int Start, int End); + + int QuerySbVPos(); + int SetSbVPos(int Start, int Amount, int Total); + int SetSbHPos(int Start, int Amount, int Total); + int ExpandHeight(int DeltaY); + + int UpdateCursor(); + int PMShowCursor(); + int PMHideCursor(); + int PMSetCursorPos(); +}; + +class GFramePeer { +public: + GFrame *Frame; + HWND hwndFrame; + HWND menuBar; + HWND hwndToolBar; + PFNWP oldFrameProc; + + GFramePeer(GFrame *aFrame, int Width, int Height); + ~GFramePeer(); + + int ConSetTitle(char *Title, char *STitle); + int ConGetTitle(char *Title, int MaxLen, char *STitle, int SMaxLen); + + int ConSetSize(int X, int Y); + int ConQuerySize(int *X, int *Y); + void MapFrame(); + void ShowFrame(); + void SizeFrame(); +}; + +int ShowVScroll = 1; +int ShowHScroll = 0; +int ShowMenuBar = 1; +int ShowToolBar = 1; +unsigned long HaveGUIDialogs = + GUIDLG_FILE | + GUIDLG_CHOICE | + GUIDLG_FIND | + GUIDLG_FINDREPLACE | + GUIDLG_PROMPT; +extern int PMDisableAccel; + +GFrame *frames = 0; +GUI *gui = 0; + +GView *MouseCapture = 0; +GView *FocusCapture = 0; + +static HEV WorkerStarted, StartInterface; + +HWND CreatePMMainMenu(HWND parent, HWND owner, char *Name); +HWND CreatePMMenu(HWND parent, HWND owner, int menu, int id, int style); +HWND CreateToolBar(HWND parent, HWND owner, int id); + +MRESULT EXPENTRY FrameWndProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2); +//MRESULT EXPENTRY SizerWndProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2); +MRESULT EXPENTRY AVIOWndProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2); +MRESULT EXPENTRY ObjectWndProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2); +MRESULT EXPENTRY CreatorWndProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2); + +HAB hab = 0; +HAB habW = 0; +static char szClient[] = "EViewer"; +static char szObject[] = "EWorker"; +static char szCreator[] = "ECreator"; +//static char szSizeBar[] = "ESizeBar" // TODO +static ULONG flFrame = + FCF_TITLEBAR | FCF_SYSMENU | + FCF_SIZEBORDER | FCF_MAXBUTTON | FCF_HIDEBUTTON | + FCF_SHELLPOSITION | FCF_TASKLIST | +// FCF_VERTSCROLL | FCF_HORZSCROLL | + FCF_MENU | FCF_ICON; + +SWP swp; +HMQ hmq = 0; +HMQ hmqW = 0; +HMTX hmtxPMData = 0; +ULONG cxScreen, cyScreen, + cyTitleBar, //cyMenuBar, + cxBorder, cyBorder, + cxScrollBar, cyScrollBar; +SHORT reportSize = 1; +TEvent EventBuf = { evNone }; +HWND hwndCreatorUser, hwndCreatorWorker; +char dragname[CCHMAXPATH]; + +#ifdef OLD_PMMENUTOOLBAR /* implemented using menus */ + +struct { + int id; + HBITMAP handle; + int cmd; + int flags; +} tools[] = +{ +// { 101, 0, ExExitEditor, MIS_BITMAP }, +// { 0, 0, 0, MIS_SEPARATOR }, + { 102, 0, ExFileOpen, MIS_BITMAP }, + { 103, 0, ExFileSave, MIS_BITMAP }, + { 104, 0, ExFileClose, MIS_BITMAP }, + { 0, 0, 0, MIS_SEPARATOR }, + { 105, 0, ExFilePrev, MIS_BITMAP }, + { 106, 0, ExFileLast, MIS_BITMAP }, + { 107, 0, ExFileNext, MIS_BITMAP }, + { 0, 0, 0, MIS_SEPARATOR }, + { 108, 0, ExUndo, MIS_BITMAP }, + { 109, 0, ExRedo, MIS_BITMAP }, + { 0, 0, 0, MIS_SEPARATOR }, + { 110, 0, ExBlockCut, MIS_BITMAP }, + { 111, 0, ExBlockCopy, MIS_BITMAP }, + { 112, 0, ExBlockPasteStream, MIS_BITMAP }, + { 113, 0, ExBlockPasteColumn, MIS_BITMAP }, + { 0, 0, 0, MIS_SEPARATOR }, + { 114, 0, ExCompilePrevError, MIS_BITMAP }, + { 115, 0, ExCompileNextError, MIS_BITMAP }, + { 0, 0, 0, MIS_SEPARATOR }, + { 116, 0, ExTagFindWord, MIS_BITMAP }, + { 119, 0, ExTagPop, MIS_BITMAP }, + { 117, 0, ExTagNext, MIS_BITMAP }, + { 118, 0, ExTagPrev, MIS_BITMAP }, +}; + +HWND CreateToolBar(HWND parent, HWND owner, int id) { + HWND menu; + int i; + MENUITEM item; + HPS ps; + + menu = WinCreateWindow(parent, + WC_MENU, "menu", WS_VISIBLE | MS_ACTIONBAR, + 0, 0, 0, 0, + owner, HWND_TOP, id, 0, 0); + + //WinEnableWindowUpdate(hmenu, FALSE); + + ps = WinGetPS(menu); + for (i = 0; i < sizeof(tools)/sizeof(tools[0]); i++) { + if (tools[i].handle == 0 && (tools[i].flags & MIS_BITMAP)) { + tools[i].handle = GpiLoadBitmap(ps, NULLHANDLE, tools[i].id, 0, 0); + } + memset((void *)&item, 0, sizeof(item)); + item.iPosition = i; + item.hwndSubMenu = 0; + item.afStyle = tools[i].flags; + item.id = tools[i].cmd + 16384 + 8192; + item.afAttribute = 0; + item.hItem = tools[i].handle; + WinSendMsg(menu, MM_INSERTITEM, MPFROMP(&item), MPFROMP(0)); + } + WinReleasePS(ps); + + return menu; +} +#else +#include "pm_tool.h" +#include "pm_tool.cpp" + +#define CMD(x) ((x) + 16384 + 8192) + +ToolBarItem tools[] = +{ + // { tiBITMAP, 101, CMD(ExExitEditor), 0, 0 }, + { tiBITMAP, 102, CMD(ExFileOpen), 0, 0 }, + { tiBITMAP, 103, CMD(ExFileSave), 0, 0 }, + { tiBITMAP, 104, CMD(ExFileClose), 0, 0 }, + { tiSEPARATOR, 0, 0, 0, 0}, + { tiBITMAP, 105, CMD(ExFilePrev), 0, 0 }, + { tiBITMAP, 106, CMD(ExFileLast), 0, 0 }, + { tiBITMAP, 107, CMD(ExFileNext), 0, 0 }, + { tiSEPARATOR, 0, 0, 0, 0}, + { tiBITMAP, 108, CMD(ExUndo), 0, 0 }, + { tiBITMAP, 109, CMD(ExRedo), 0, 0 }, + { tiSEPARATOR, 0, 0, 0, 0}, + { tiBITMAP, 110, CMD(ExBlockCut), 0, 0 }, + { tiBITMAP, 111, CMD(ExBlockCopy), 0, 0 }, + { tiBITMAP, 112, CMD(ExBlockPasteStream), 0, 0 }, + { tiBITMAP, 113, CMD(ExBlockPasteColumn), 0, 0 }, + { tiSEPARATOR, 0, 0, 0, 0}, + { tiBITMAP, 114, CMD(ExCompilePrevError), 0, 0 }, + { tiBITMAP, 115, CMD(ExCompileNextError), 0, 0 }, + { tiSEPARATOR, 0, 0, 0, 0}, + { tiBITMAP, 116, CMD(ExTagFindWord), 0, 0 }, + { tiBITMAP, 119, CMD(ExTagPop), 0, 0 }, + { tiBITMAP, 117, CMD(ExTagNext), 0, 0 }, + { tiBITMAP, 118, CMD(ExTagPrev), 0, 0 }, +}; + +HWND CreateToolBar(HWND parent, HWND owner, int id) { + STARTFUNC("CreateToolBar{g_pm.cpp}"); + static int reged = 0; + HPS hps; + unsigned int i; + + if (!reged) { + RegisterToolBarClass(hab); + reged = 1; + } + + hps = WinGetPS(parent); + + for (i = 0; i < sizeof(tools)/sizeof(tools[0]); i++) + { + if (tools[i].hBitmap == 0 && (tools[i].ulType == tiBITMAP)) + tools[i].hBitmap = GpiLoadBitmap(hps, NULLHANDLE, tools[i].ulId, 0, 0); + } + + WinReleasePS(hps); + + return CreateToolBar(parent, owner, id, + sizeof(tools)/sizeof(tools[0]), + tools); +} + +#endif + +HWND CreatePMMenu(HWND parent, HWND owner, int menu, int id, int style) { + HWND hmenu; + int i; + MENUITEM item; + char s[256]; + char *p; + + hmenu = WinCreateWindow(parent, + WC_MENU, "menu", style & ~MS_CONDITIONALCASCADE, + 0, 0, 0, 0, + owner, HWND_TOP, id, 0, 0); + + //WinEnableWindowUpdate(hmenu, FALSE); + + for (i = 0; i < Menus[menu].Count; i++) { + memset((void *)&item, 0, sizeof(item)); + item.iPosition = i; + item.hwndSubMenu = 0; + if (Menus[menu].Items[i].Name) { + if (Menus[menu].Items[i].SubMenu != -1) { + item.afStyle = MIS_SUBMENU | MIS_TEXT; + item.hwndSubMenu = CreatePMMenu(HWND_DESKTOP, owner, + Menus[menu].Items[i].SubMenu, 0, + (Menus[menu].Items[i].Cmd == SUBMENU_CONDITIONAL) ? MS_CONDITIONALCASCADE : 0); + { + static ids = 1000; + item.id = ids++; + if (ids == 7000) { + ids = 1000; + } + } + } else { + item.afStyle = MIS_TEXT; + item.id = (Menus[menu].Items[i].Cmd & 0xFFFF) + 8192; // ? + } + } else { + item.afStyle = MIS_SEPARATOR; + item.id = 0; + } + item.afAttribute = 0; + item.hItem = 0; + if (Menus[menu].Items[i].Name) { + strcpy(s, Menus[menu].Items[i].Name); + p = strchr(s, '&'); + if (p) + (*p) = '~'; + p = (char *)&s; + } else { + p = 0; + } + WinSendMsg(hmenu, MM_INSERTITEM, MPFROMP(&item), MPFROMP(p)); + if (i == 0 && style == MS_CONDITIONALCASCADE) { + WinSetWindowBits(hmenu, QWL_STYLE, + MS_CONDITIONALCASCADE, MS_CONDITIONALCASCADE); + WinSendMsg(hmenu, MM_SETDEFAULTITEMID, MPFROMSHORT(item.id), 0); + } + } + //WinEnableWindowUpdate(hmenu, TRUE); + return hmenu; +} + +HWND CreatePMMainMenu(HWND parent, HWND owner, char *Name) { + int id = GetMenuId(Name); + HWND main; + + assert (id != -1); + + main = CreatePMMenu(parent, owner, id, FID_MENU, MS_ACTIONBAR); + return main; +} + +#include "pmdlg.h" + +void InsertHistory(HWND hwnd, int id, int maxlen) { + int i, count; + char *str; + count = CountInputHistory(id); + + str = (char *)malloc(maxlen + 1); + if (str == 0) + return; + + for (i = 0; i < count; i++) { + if (GetInputHistory(id, str, maxlen, i + 1) == 1) + WinInsertLboxItem(hwnd, LIT_END, str); + } + free(str); +} + +MRESULT EXPENTRY FileDlgProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2) { + FILEDLG *dlg; + + dlg = (FILEDLG *)WinQueryWindowULong(hwnd, QWL_USER); + + switch (msg) { + case WM_INITDLG: + WinSendMsg(hwnd, WM_SETICON, + MPFROMLONG(WinLoadPointer(HWND_DESKTOP, 0, 1)), 0); + + InsertHistory(WinWindowFromID(hwnd, DID_FILENAME_ED), HIST_PATH, MAXPATH); + WinInvalidateRect(hwnd, 0, TRUE); + WinRestoreWindowPos("FTEPM", + ((dlg->fl & FDS_SAVEAS_DIALOG) ? "FileSaveDlg" : "FileOpenDlg"), + hwnd); + break; + case WM_COMMAND: + switch (SHORT1FROMMP(mp1)) { + case DID_OK: + WinShowWindow(hwnd, FALSE); + WinStoreWindowPos("FTEPM", + ((dlg->fl & FDS_SAVEAS_DIALOG) ? "FileSaveDlg" : "FileOpenDlg"), + hwnd); + break; + + case DID_CANCEL: + WinShowWindow(hwnd, FALSE); + WinStoreWindowPos("FTEPM", + ((dlg->fl & FDS_SAVEAS_DIALOG) ? "FileSaveDlg" : "FileOpenDlg"), + hwnd); + break; + } + break; + case WM_CLOSE: + WinShowWindow(hwnd, FALSE); + WinStoreWindowPos("FTEPM", + ((dlg->fl & FDS_SAVEAS_DIALOG) ? "FileSaveDlg" : "FileOpenDlg"), + hwnd); + break; + } + return WinDefFileDlgProc(hwnd, msg, mp1, mp2); +} + +int DLGGetFile(GView *View, const char *Prompt, unsigned int BufLen, char *FileName, int Flags) { + FILEDLG dlg; + + memset((void *)&dlg, 0, sizeof(dlg)); + + dlg.cbSize = sizeof(dlg); + dlg.fl = + /*FDS_CENTER |*/ FDS_CUSTOM | + ((Flags & GF_SAVEAS) ? FDS_SAVEAS_DIALOG : FDS_OPEN_DIALOG); + dlg.pszTitle = (char*)Prompt; + strcpy(dlg.szFullFile, FileName); + dlg.hMod = NULLHANDLE; + dlg.usDlgId = IDD_FILEDLG; + dlg.pfnDlgProc = FileDlgProc; + + if (!LONGFROMMR(WinSendMsg(View->Parent->Peer->hwndFrame, + UWM_FILEDIALOG, MPFROMP(&dlg), 0))) + return 0; + + if (dlg.lReturn == DID_OK) { + strncpy(FileName, dlg.szFullFile, BufLen); + FileName[BufLen - 1] = 0; + AddInputHistory(HIST_PATH, FileName); + return 1; + } + return 0; +} + +typedef struct { + char *Title; + int NSel; + va_list ap; + int Flags; +} ChoiceInfo; + +static int DoChoice(HWND hwndFrame, ChoiceInfo *choice) { + char msg[1024]; + char Prompt[1024]; + char *fmt; + char *p; + int rc; + HWND hwndDlg; + HWND hwndStatic; + HWND hwndButton[40]; + int cyBorder, cxBorder; + SWP swp, swp1; + int i, x, y; + ULONG flFrame = FCF_TITLEBAR | FCF_SYSMENU | FCF_DLGBORDER; + HPS ps; + int xw, yw, nx, ny; + RECTL tr; + int cp, cd; + char msgbox[100]; + int SPC = 4; + + sprintf(msgbox, "MsgBox: %s", choice->Title); + + cxBorder = WinQuerySysValue(HWND_DESKTOP, SV_CXDLGFRAME); + cyBorder = WinQuerySysValue(HWND_DESKTOP, SV_CYDLGFRAME); + + hwndDlg = WinCreateStdWindow(HWND_DESKTOP, + WS_VISIBLE, + &flFrame, + 0, + choice->Title, + 0, + 0, + 0, 0); + + WinSendMsg(hwndDlg, WM_SETICON, + MPFROMLONG(WinLoadPointer(HWND_DESKTOP, 0, 1)), 0); + + WinSetOwner(hwndDlg, hwndFrame); + + x = SPC; + for (i = 0; i < choice->NSel; i++) { + char button[60]; + strcpy(button, va_arg(choice->ap, char *)); + p = strchr(button, '&'); + if (p) + *p = '~'; + + hwndButton[i] = + WinCreateWindow(hwndDlg, + WC_BUTTON, + button, + WS_VISIBLE | BS_PUSHBUTTON | BS_AUTOSIZE | ((i == 0) ? BS_DEFAULT | WS_TABSTOP | WS_GROUP: 0), + cxBorder + x, SPC + cyBorder, 0, 0, + hwndDlg, ((i == 0) ? HWND_TOP: hwndButton[i - 1]), + 200 + i, + NULL, NULL); + + WinQueryWindowPos(hwndButton[i], &swp); + x += SPC + swp.cx; + } + + fmt = va_arg(choice->ap, char *); + vsprintf(msg, fmt, choice->ap); + strncpy((PCHAR)Prompt, msg, sizeof(Prompt)); + Prompt[sizeof(Prompt) - 1] = 0; + + hwndStatic = WinCreateWindow(hwndDlg, + WC_STATIC, + Prompt, + WS_VISIBLE | SS_TEXT | DT_TOP | DT_LEFT | DT_WORDBREAK, + 0, 0, 0, 0, + hwndDlg, HWND_TOP, + 100, + NULL, NULL); + + WinRestoreWindowPos("FTEPM", msgbox, hwndDlg); + + xw = cxScreen / 2; + if (x - SPC > xw) + xw = x - SPC; + + yw = 0; + ps = WinGetPS(hwndStatic); + + cp = 0; + for (;;) { + tr.xLeft = 0; + tr.xRight = xw; + tr.yTop = cyScreen / 2; + tr.yBottom = 0; + + cd = WinDrawText(ps, -1, (Prompt + cp), + &tr, + 0, 0, + DT_LEFT | DT_TOP | DT_WORDBREAK | DT_TEXTATTRS | + DT_QUERYEXTENT | DT_EXTERNALLEADING); + if (!cd) + break; + cp += cd; + yw += tr.yTop - tr.yBottom; + } + + WinReleasePS(ps); + + WinSetWindowPos(hwndStatic, 0, + cxBorder + SPC, + cyBorder + SPC + swp.cy + SPC, + xw, yw, SWP_MOVE | SWP_SIZE); + + WinQueryWindowPos(hwndStatic, &swp1); + WinQueryWindowPos(hwndButton[0], &swp); + + nx = cxBorder + SPC + xw + SPC + cxBorder; + ny = cyBorder + SPC + swp.cy + SPC + swp1.cy + SPC + cyTitleBar + cyBorder; + + WinQueryWindowPos(hwndDlg, &swp); + + x = swp.x; + y = swp.y + swp.cy - ny; + + if (y < cyBorder) y = - cyBorder; + if (y + ny >= cyScreen + cyBorder) y = cyScreen - ny + cyBorder; + if (x + nx >= cxScreen + cxBorder) x = cxScreen - nx + cxBorder; + if (x < -cxBorder) x = -cxBorder; + + WinSetWindowPos(hwndDlg, 0, + x, y, + nx, ny, + SWP_SIZE | SWP_SHOW | SWP_MOVE | SWP_ACTIVATE); + + WinSubclassWindow(hwndDlg, (PFNWP) WinDefDlgProc); + + if (choice->Flags & (GPC_ERROR | GPC_FATAL)) + WinAlarm(HWND_DESKTOP, WA_ERROR); + else if (choice->Flags & (GPC_CONFIRM)) + WinAlarm(HWND_DESKTOP, WA_NOTE); + else if (choice->Flags & (GPC_WARNING)) + WinAlarm(HWND_DESKTOP, WA_WARNING); + + rc = LONGFROMMR(WinSendMsg(hwndFrame, UWM_PROCESSDLG, + MPFROMLONG(hwndDlg), 0)); + + WinStoreWindowPos("FTEPM", msgbox, hwndDlg); + + WinSendMsg(hwndFrame, UWM_DESTROYHWND, MPFROMLONG(hwndDlg), 0); + if (rc == DID_CANCEL || rc == DID_ERROR) + return choice->NSel - 1; + + if (rc >= 200 && rc < choice->NSel + 200) + return rc - 200; + + return 0; +} + +/* reimplemented most of the WinMessageBox code to get store/restore position to work */ +int DLGPickChoice(GView *View, const char *ATitle, int NSel, va_list ap, int Flags) { + ChoiceInfo choice; + + choice.Title = (char *)ATitle; + choice.NSel = NSel; + choice.ap = ap; + choice.Flags = Flags; + return LONGFROMMR(WinSendMsg(View->Parent->Peer->hwndFrame, UWM_CHOICE, MPFROMP(&choice), 0)); +} + +static struct { + char *Title; + char *Entry; + int MaxLen; + int HistId; +} PromptInfo; + +MRESULT EXPENTRY PromptDlgProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2) { + switch (msg) { + case WM_INITDLG: + WinSendMsg(hwnd, WM_SETICON, + MPFROMLONG(WinLoadPointer(HWND_DESKTOP, 0, 1)), 0); + + WinSendDlgItemMsg(hwnd, IDE_FIELD, EM_SETTEXTLIMIT, MPFROMLONG(PromptInfo.MaxLen), 0); + WinSetDlgItemText(hwnd, IDE_FIELD, PromptInfo.Entry); + InsertHistory(WinWindowFromID(hwnd, IDE_FIELD), PromptInfo.HistId, PromptInfo.MaxLen); + WinSetDlgItemText(hwnd, IDS_PROMPT, PromptInfo.Title); + WinSetWindowText(hwnd, PromptInfo.Title); + WinInvalidateRect(hwnd, 0, TRUE); + WinRestoreWindowPos("FTEPM", "PromptDlg", hwnd); + return WinDefDlgProc(hwnd, msg, mp1, mp2); + + case WM_COMMAND: + switch (SHORT1FROMMP(mp1)) { + case DID_OK: + WinQueryDlgItemText(hwnd, IDE_FIELD, PromptInfo.MaxLen, PromptInfo.Entry); + PromptInfo.Entry[PromptInfo.MaxLen - 1] = 0; + AddInputHistory(PromptInfo.HistId, PromptInfo.Entry); + + WinShowWindow(hwnd, FALSE); + WinStoreWindowPos("FTEPM", "PromptDlg", hwnd); + WinDismissDlg(hwnd, TRUE); + return (MRESULT)FALSE; + + case DID_CANCEL: + WinShowWindow(hwnd, FALSE); + WinStoreWindowPos("FTEPM", "PromptDlg", hwnd); + WinDismissDlg(hwnd, FALSE); + return (MRESULT)FALSE; + } + break; + case WM_CLOSE: + WinShowWindow(hwnd, FALSE); + WinStoreWindowPos("FTEPM", "PromptDlg", hwnd); + /* passthru */ + default: + return WinDefDlgProc(hwnd, msg, mp1, mp2); + } + return (MRESULT)FALSE; +} + +int DLGGetStr(GView *View, const char *Prompt, unsigned int BufLen, char *Str, int HistId, int Flags) { + assert(BufLen > 0); + PromptInfo.MaxLen = BufLen - 1; + PromptInfo.Title = (char *)Prompt; + PromptInfo.Entry = Str; + PromptInfo.HistId = HistId; + + if (LONGFROMMR(WinSendMsg(View->Parent->Peer->hwndFrame, + UWM_DLGBOX, MPFROMP(PFNWP(PromptDlgProc)), MPFROMLONG(IDD_PROMPT))) != DID_OK) + return 0; + + return 1; +} + +static SearchReplaceOptions SearchOpt; +static int ReplaceDlg = 0; + +MRESULT EXPENTRY FindDlgProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2) { + switch (msg) { + case WM_INITDLG: + WinSendMsg(hwnd, WM_SETICON, + MPFROMLONG(WinLoadPointer(HWND_DESKTOP, 0, 1)), 0); + + WinSendDlgItemMsg(hwnd, IDE_FIND, EM_SETTEXTLIMIT, MPFROMLONG(MAXSEARCH), 0); + WinSetDlgItemText(hwnd, IDE_FIND, SearchOpt.strSearch); + InsertHistory(WinWindowFromID(hwnd, IDE_FIND), HIST_SEARCH, MAXSEARCH); + WinCheckButton(hwnd, IDC_IGNORECASE, (SearchOpt.Options & SEARCH_NCASE) ? 1 : 0); + WinCheckButton(hwnd, IDC_REGEXPS, (SearchOpt.Options & SEARCH_RE) ? 1 : 0); + WinCheckButton(hwnd, IDC_WORDS, (SearchOpt.Options & SEARCH_WORD) ? 1 : 0); + WinCheckButton(hwnd, IDC_BLOCK, (SearchOpt.Options & SEARCH_BLOCK) ? 1 : 0); + WinCheckButton(hwnd, IDC_GLOBAL, (SearchOpt.Options & SEARCH_GLOBAL) ? 1 : 0); + WinCheckButton(hwnd, IDC_REVERSE, (SearchOpt.Options & SEARCH_BACK) ? 1 : 0); + WinCheckButton(hwnd, IDC_ALLOCCURENCES, (SearchOpt.Options & SEARCH_ALL) ? 1 : 0); + WinCheckButton(hwnd, IDC_JOINLINE, (SearchOpt.Options & SEARCH_JOIN) ? 1: 0); + if (ReplaceDlg) { + WinSendDlgItemMsg(hwnd, IDE_REPLACE, EM_SETTEXTLIMIT, MPFROMLONG(MAXSEARCH), 0); + WinSetDlgItemText(hwnd, IDE_REPLACE, SearchOpt.strReplace); + InsertHistory(WinWindowFromID(hwnd, IDE_REPLACE), HIST_SEARCH, MAXSEARCH); + WinCheckButton(hwnd, IDC_NOPROMPTING, (SearchOpt.Options & SEARCH_NASK) ? 1 : 0); + } else { + WinCheckButton(hwnd, IDC_DELETELINE, (SearchOpt.Options & SEARCH_DELETE) ? 1 : 0); + } + WinInvalidateRect(hwnd, 0, TRUE); + WinRestoreWindowPos("FTEPM", ReplaceDlg ? "ReplaceDlg" : "FindDlg", hwnd); + return WinDefDlgProc(hwnd, msg, mp1, mp2); + + case WM_COMMAND: + switch (SHORT1FROMMP(mp1)) { + case DID_OK: + SearchOpt.ok = 1; + SearchOpt.resCount = 0; + SearchOpt.Options = 0; + strcpy(SearchOpt.strReplace, ""); + WinQueryDlgItemText(hwnd, IDE_FIND, MAXSEARCH, SearchOpt.strSearch); + SearchOpt.strSearch[MAXSEARCH - 1] = 0; + AddInputHistory(HIST_SEARCH, SearchOpt.strSearch); + + if (WinQueryButtonCheckstate(hwnd, IDC_IGNORECASE)) + SearchOpt.Options |= SEARCH_NCASE; + if (WinQueryButtonCheckstate(hwnd, IDC_REGEXPS)) + SearchOpt.Options |= SEARCH_RE; + if (WinQueryButtonCheckstate(hwnd, IDC_WORDS)) + SearchOpt.Options |= SEARCH_WORD; + if (WinQueryButtonCheckstate(hwnd, IDC_BLOCK)) + SearchOpt.Options |= SEARCH_BLOCK; + if (WinQueryButtonCheckstate(hwnd, IDC_GLOBAL)) + SearchOpt.Options |= SEARCH_GLOBAL; + if (WinQueryButtonCheckstate(hwnd, IDC_REVERSE)) + SearchOpt.Options |= SEARCH_BACK; + if (WinQueryButtonCheckstate(hwnd, IDC_ALLOCCURENCES)) + SearchOpt.Options |= SEARCH_ALL; + if (WinQueryButtonCheckstate(hwnd, IDC_JOINLINE)) + SearchOpt.Options |= SEARCH_JOIN; + + if (ReplaceDlg) { + WinQueryDlgItemText(hwnd, IDE_REPLACE, MAXSEARCH, SearchOpt.strReplace); + SearchOpt.strReplace[MAXSEARCH - 1] = 0; + AddInputHistory(HIST_SEARCH, SearchOpt.strReplace); + SearchOpt.Options |= SEARCH_REPLACE; + if (WinQueryButtonCheckstate(hwnd, IDC_NOPROMPTING)) + SearchOpt.Options |= SEARCH_NASK; + } else { + if (WinQueryButtonCheckstate(hwnd, IDC_DELETELINE)) + SearchOpt.Options |= SEARCH_DELETE; + } + + WinShowWindow(hwnd, FALSE); + WinStoreWindowPos("FTEPM", ReplaceDlg ? "ReplaceDlg" : "FindDlg", hwnd); + WinDismissDlg(hwnd, TRUE); + return (MRESULT)FALSE; + + case DID_CANCEL: + WinShowWindow(hwnd, FALSE); + WinStoreWindowPos("FTEPM", ReplaceDlg ? "ReplaceDlg" : "FindDlg", hwnd); + WinDismissDlg(hwnd, FALSE); + return (MRESULT)FALSE; + } + break; + case WM_CLOSE: + WinShowWindow(hwnd, FALSE); + WinStoreWindowPos("FTEPM", ReplaceDlg ? "ReplaceDlg" : "FindDlg", hwnd); + /* passthru */ + default: + return WinDefDlgProc(hwnd, msg, mp1, mp2); + } + return (MRESULT)FALSE; +} + +int DLGGetFind(GView *View, SearchReplaceOptions &sr) { + SearchOpt = sr; + ReplaceDlg = 0; + + if (LONGFROMMR(WinSendMsg(View->Parent->Peer->hwndFrame, UWM_DLGBOX, + PVOIDFROMMP(PFNWP(FindDlgProc)), MPFROMLONG(IDD_FIND))) != DID_OK) + return 0; + + sr = SearchOpt; + + return 1; +} + +int DLGGetFindReplace(GView *View, SearchReplaceOptions &sr) { + SearchOpt = sr; + ReplaceDlg = 1; + + if (LONGFROMMR(WinSendMsg(View->Parent->Peer->hwndFrame, UWM_DLGBOX, + PVOIDFROMMP(PFNWP(FindDlgProc)), MPFROMLONG(IDD_FINDREPLACE))) != DID_OK) + return 0; + + sr = SearchOpt; + + return 1; +} + +struct { + int vk; + TKeyCode kc; + char *name; +} lvirt[] = { +{ VK_F1, kbF1, "F1" }, +{ VK_F2, kbF2, "F2" }, +{ VK_F3, kbF3, "F3" }, +{ VK_F4, kbF4, "F4" }, +{ VK_F5, kbF5, "F5" }, +{ VK_F6, kbF6, "F6" }, +{ VK_F7, kbF7, "F7" }, +{ VK_F8, kbF8, "F8" }, +{ VK_F9, kbF9, "F9" }, +{ VK_F10, kbF10, "F10" }, +{ VK_F11, kbF11, "F11" }, +{ VK_F12, kbF12, "F12" }, + +{ VK_ESC, kbEsc, "Esc" }, +{ VK_ENTER, kbEnter | kfGray, "Enter" }, +{ VK_NEWLINE, kbEnter, "Enter" }, +{ VK_BACKSPACE, kbBackSp, "BackSp" }, +{ VK_SPACE, kbSpace, "Space" }, +{ VK_TAB, kbTab, "Tab" }, +{ VK_BACKTAB, kbTab | kfShift, "Tab" }, + +{ VK_UP, kbUp, "Up" }, +{ VK_DOWN, kbDown, "Down" }, +{ VK_LEFT, kbLeft, "Left" }, +{ VK_RIGHT, kbRight, "Right" }, +{ VK_HOME, kbHome, "Home" }, +{ VK_END, kbEnd, "End" }, +{ VK_PAGEDOWN, kbPgDn, "PgDn" }, +{ VK_PAGEUP, kbPgUp, "PgUp" }, +{ VK_INSERT, kbIns, "Ins" }, +{ VK_DELETE, kbDel, "Del" }, + +{ VK_CTRL, kbCtrl | kfModifier, "Ctrl" }, +{ VK_ALT, kbAlt | kfModifier, "Alt" }, +{ VK_ALTGRAF, kbAlt | kfModifier, "Alt" }, +{ VK_SHIFT, kbShift | kfModifier, "Shift" }, +{ VK_CAPSLOCK, kbCapsLock | kfModifier, "CapsLock" }, +{ VK_NUMLOCK, kbNumLock | kfModifier, "NumLock" }, +{ VK_SCRLLOCK, kbScrollLock | kfModifier, "ScrollLock" }, +{ VK_BREAK, kbBreak, "Break" }, +{ VK_PAUSE, kbPause, "Pause" }, +{ VK_PRINTSCRN, kbPrtScr, "PrtScr" }, +{ VK_SYSRQ, kbSysReq, "SysReq", }, +}; + +char *ConvertKey(int ch, int virt, int flags, int scan, TEvent &Event) { + int keyFlags = 0; + static char name[40]; + char keyname[40]; + TKeyCode keyCode = 0; + + strcpy(keyname, "UNKNOWN"); + + //printf("ch:%d, virt:%d, flags:%d, scan:%d\n", ch, virt, flags, scan); + + name[0] = 0; + + if (flags & KC_CTRL) + keyFlags |= kfCtrl; + if (flags & KC_ALT) + keyFlags |= kfAlt; + if (flags & KC_SHIFT) + keyFlags |= kfShift; + if ((ch != 0xE0) && ((ch & 0xFF) == 0xE0)) + keyFlags |= kfGray; + + if (keyFlags == kfAlt) {// do not produce anything on alt+XXX + switch (scan) { + case 71: case 72: case 73: + case 75: case 76: case 77: + case 79: case 80: case 81: + case 82: case 83: + return name; + } + } + if (ch != 0 && (flags & KC_CHAR)) { + switch (scan) { + case 71: case 72: case 73: + case 75: case 76: case 77: + case 79: case 80: case 81: + case 82: case 83: + virt = 0; + } + } + { + int i; + + for (i = 0; i < (sizeof(lvirt)/sizeof(lvirt[0])); i++) + if (lvirt[i].vk == virt) { + keyCode = lvirt[i].kc; + strcpy(keyname, lvirt[i].name); + break; + } + } + if (keyCode == 0) { + char c[2]; + + if( ch == 0 && scan == 86 ){ + // Fix for OS/2 bug with UK keyboard layout + // This is shift-'\' (to the left of Z), which returns 0 + ch = '|'; + } + + c[0] = char(ch); + c[1] = 0; + + if (ch == '+' && scan == 78) + keyCode = '+' | kfGray; + else if (ch == '-' && scan == 74) + keyCode = '-' | kfGray; + else if (ch == '*' && scan == 55) + keyCode = '*' | kfGray; + else if (ch == '/' && scan == 92) + keyCode = '/' | kfGray; + else { + keyCode = ch; + //if (keyFlags == kfShift) + // keyFlags = 0; + } + + keyname[0] = 0; + + if (keyCode & kfGray) + strcpy(keyname, "G+"); + + strcat(keyname, c); + } + + if ((keyFlags & (kfAlt | kfSpecial | kfGray)) == kfAlt) { + if (keyCode >= 'a' && keyCode <= 'z') + keyCode -= 'a' - 'A'; + } + + if ((keyFlags & (kfCtrl | kfAlt | kfSpecial | kfGray)) == kfCtrl) { + if (keyCode >= 'a' && keyCode < 'a' + 32) + keyCode -= 'a' - 1; + else if (keyCode >= 'A' && keyCode < 'A' + 32) + keyCode -= 'A' - 1; + } + + if (keyFlags & kfCtrl) + if (keyCode < 32) + keyCode += 64; + + keyCode |= keyFlags; + + if (keyCode & kfKeyUp) + strcat(name, "UP "); + else + strcat(name, "DN "); + if (keyCode & kfAlt) + strcat(name, "A+"); + if (keyCode & kfCtrl) + strcat(name, "C+"); + if (keyCode & kfGray) + strcat(name, "G+"); + if (keyCode & kfShift) + strcat(name, "S+"); + strcat(name, keyname); + + Event.What = evKeyDown; + if (flags & KC_KEYUP) { + keyFlags |= kfKeyUp; + Event.What = evKeyUp; + } + Event.Key.Code = keyCode; + return name; +} + +MRESULT CreateChild(HWND parent, GViewPeer *peer, PMData *pmData) { + PMPTR ptr; + + ptr.len = sizeof(PMPTR); + ptr.p = pmData; + + peer->hwndView = WinCreateWindow(parent, + szClient, "FTE", + WS_VISIBLE, 0, 0, 0, 0, + NULLHANDLE, HWND_TOP, FID_CLIENT, + (void *)&ptr, NULL); + + assert(peer->hwndView != NULLHANDLE); + + peer->hwndVscroll = WinCreateWindow(parent, + WC_SCROLLBAR, "", + WS_VISIBLE | SBS_VERT | SBS_AUTOTRACK, 0, 0, 0, 0, + peer->hwndView, HWND_TOP, 0, + (void *)&ptr, NULL); + + assert(peer->hwndVscroll != NULLHANDLE); + + peer->hwndHscroll = WinCreateWindow(parent, + WC_SCROLLBAR, "", + WS_VISIBLE | SBS_HORZ | SBS_AUTOTRACK, 0, 0, 0, 0, + peer->hwndView, HWND_TOP, 0, + (void *)&ptr, NULL); + + assert(peer->hwndHscroll != NULLHANDLE); + + return (MRESULT)TRUE; +} + +BOOL CalcFrameSWP(HWND hwnd, PSWP pswp, BOOL bFrame) { + BOOL bSuccess; + RECTL rcl; + + rcl.xLeft = pswp->x; + rcl.yBottom = pswp->y; + rcl.xRight = pswp->x + pswp->cx; + rcl.yTop = pswp->y + pswp->cy; + + bSuccess = WinCalcFrameRect(hwnd, &rcl, bFrame); + + pswp->x = rcl.xLeft; + pswp->y = rcl.yBottom; + pswp->cx = rcl.xRight - rcl.xLeft; + pswp->cy = rcl.yTop - rcl.yBottom; + + return bSuccess; +} + +MRESULT EXPENTRY FrameWndProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2) { + GFramePeer *peer = (GFramePeer *) WinQueryWindowULong(hwnd, QWL_USER); + + if (peer) switch (msg) { + case UWM_DESTROY: + WinDestroyWindow(hwnd); + return 0; + + case UWM_DESTROYHWND: + WinDestroyWindow(LONGFROMMP(mp1)); + return 0; + + case UWM_FILEDIALOG: + return MRFROMLONG(WinFileDlg(HWND_DESKTOP, hwnd, (FILEDLG *)PVOIDFROMMP(mp1))); + + case UWM_DLGBOX: + return MRFROMLONG(WinDlgBox(HWND_DESKTOP, hwnd, + PFNWP(PVOIDFROMMP(mp1)), 0, LONGFROMMP(mp2), NULL)); + + case UWM_PROCESSDLG: + return MRFROMLONG(WinProcessDlg(HWNDFROMMP(mp1))); + + case UWM_CHOICE: + return MRFROMLONG(DoChoice(hwnd, (ChoiceInfo *)PVOIDFROMMP(mp1))); + + case UWM_CREATECHILD: + //DosBeep(2500, 1000); + return CreateChild(hwnd, (GViewPeer *)PVOIDFROMMP(mp1), (PMData *)PVOIDFROMMP(mp2)); + + case WM_TRANSLATEACCEL: + // check for keys not to be translated + { + QMSG *qmsg = (QMSG *)mp1; + USHORT vk = SHORT2FROMMP((qmsg->mp2)); + USHORT fl = (USHORT)(SHORT1FROMMP((qmsg->mp1)) & (KC_ALT | KC_SHIFT | KC_CTRL | KC_KEYUP)); + USHORT ch = SHORT1FROMMP((qmsg->mp2)); + + if ((vk == VK_MENU || vk == VK_F1) && fl == 0 || + vk == VK_NEWLINE && fl == KC_ALT || + vk == VK_ENTER && fl == KC_ALT || + vk == VK_SPACE && fl == KC_ALT) + return (MRESULT)FALSE; + + if ((ch >= 'A' && ch <= 'Z' || ch >= 'a' && ch <= 'z') && + (fl & KC_ALT)) + return (MRESULT)FALSE; + + if (PMDisableAccel) + if (fl & KC_ALT) + if (vk >= VK_F1 && vk <= VK_F24) + return (MRESULT)FALSE; + + } + break; + + /*case WM_CALCFRAMERECT: + { + PRECTL rcl = (PRECTL)PVOIDFROMMP(mp1); + USHORT isFrame = SHORT1FROMMP(mp2); + BOOL fSuccess = LONGFROMMR(peer->oldFrameProc(hwnd, msg, mp1, mp2)); + + if (ShowToolBar && fSuccess) { + SWP swpToolBar; + HWND hwndToolBar = WinWindowFromID(hwnd, FID_MTOOLBAR); + + WinQueryWindowPos(hwndToolBar, &swpToolBar); + WinSendMsg(hwndToolBar, + WM_ADJUSTWINDOWPOS, + MPFROMP(&swpToolBar), + MPARAM(0)); + + if (isFrame) + rcl->yTop -= swpToolBar.cy; + else + rcl->yTop += swpToolBar.cy; + } + + return MRFROMLONG(fSuccess); + }*/ + + case WM_QUERYTRACKINFO: + { + MRESULT mr; + + mr = peer->oldFrameProc(hwnd, msg, mp1, mp2); + + if (mr == (MRESULT)FALSE) + return mr; + + DosRequestMutexSem(hmtxPMData, SEM_INDEFINITE_WAIT); + if ((SHORT1FROMMP(mp1) & TF_MOVE) != TF_MOVE) { + PTRACKINFO pti; + + pti = (PTRACKINFO) PVOIDFROMMP(mp2); + pti->cxGrid = peer->Frame->Top->Peer->pmData->cxChar; + pti->cyGrid = peer->Frame->Top->Peer->pmData->cyChar; + pti->cxKeyboard = peer->Frame->Top->Peer->pmData->cxChar; + pti->cyKeyboard = peer->Frame->Top->Peer->pmData->cyChar; + pti->fs |= TF_GRID; + } + DosReleaseMutexSem(hmtxPMData); + return mr; + } + + case WM_MINMAXFRAME: + { + PSWP pswp = (PSWP) PVOIDFROMMP(mp1); + + if (pswp->fl & SWP_MAXIMIZE) { + GView *v; + int cnt; + SWP swpMenu; + SWP swpToolBar; + HWND hwndMenu = WinWindowFromID(hwnd, FID_MENU); + HWND hwndToolBar = WinWindowFromID(hwnd, FID_MTOOLBAR); + + WinQueryWindowPos(hwndMenu, &swpMenu); + swpMenu.x = 0; + swpMenu.y = 0; + swpMenu.cx = cxScreen - 2 * cxBorder; + swpMenu.cy = cyScreen; + WinSendMsg(hwndMenu, + WM_ADJUSTWINDOWPOS, + MPFROMP(&swpMenu), + MPARAM(0)); + + if (ShowToolBar) { + WinQueryWindowPos(hwndToolBar, &swpToolBar); + swpToolBar.x = 0; + swpToolBar.y = 0; + swpToolBar.cx = cxScreen - 2 * cxBorder; + swpToolBar.cy = cyScreen; + WinSendMsg(hwndToolBar, + WM_ADJUSTWINDOWPOS, + MPFROMP(&swpToolBar), + MPARAM(0)); + } else { + swpToolBar.cy = 0; + } + + DosRequestMutexSem(hmtxPMData, SEM_INDEFINITE_WAIT); + + pswp->cx = cxScreen - cxScrollBar; + pswp->cy = cyScreen - cyTitleBar - swpMenu.cy - swpToolBar.cy; + + cnt = 0; + v = peer->Frame->Top; + while (v) { + cnt++; + v = v->Prev; + if (v == peer->Frame->Top) break; + } + + pswp->cy -= cnt * cyScrollBar; + + if (pswp->cy < 0) pswp->cy = 0; + + if (v) { + pswp->cx /= v->Peer->pmData->cxChar; + if (pswp->cx > MAXXSIZE) + pswp->cx = MAXXSIZE; + pswp->cx *= v->Peer->pmData->cxChar; + + pswp->cy /= v->Peer->pmData->cyChar; + if (pswp->cy > MAXYSIZE) + pswp->cy = MAXYSIZE; + pswp->cy *= v->Peer->pmData->cyChar; + } + + pswp->cy += cnt * cyScrollBar; + + pswp->cx += cxBorder * 2 + cxScrollBar; + pswp->cy += cyBorder * 2 + cyTitleBar + swpMenu.cy + swpToolBar.cy; + + pswp->y = cyScreen - pswp->cy + cyBorder; + + DosReleaseMutexSem(hmtxPMData); + return (MRESULT)FALSE; + } + } + break; + + case WM_ADJUSTWINDOWPOS: + { + PSWP pswp = (PSWP) PVOIDFROMMP(mp1); + + if (pswp->fl & (SWP_SIZE | SWP_MOVE | SWP_MAXIMIZE)) { + GView *v; + int cnt; + SWP swpToolBar; + + if (pswp->cx < 0 || pswp->cy <= cyTitleBar + 2 * cyBorder) + break; + + DosRequestMutexSem(hmtxPMData, SEM_INDEFINITE_WAIT); + //printf("Before 1: %d %d | %d %d\n", pswp->cx, pswp->x, pswp->cy, pswp->y); + CalcFrameSWP(hwnd, pswp, TRUE); + + if (ShowToolBar) { + HWND hwndToolBar = WinWindowFromID(hwnd, FID_MTOOLBAR); + + WinQueryWindowPos(hwndToolBar, &swpToolBar); + swpToolBar.x = 0; + swpToolBar.y = 0; + swpToolBar.cx = pswp->cx; + swpToolBar.cy = pswp->cy; + WinSendMsg(hwndToolBar, + WM_ADJUSTWINDOWPOS, + MPFROMP(&swpToolBar), + MPARAM(0)); + } else { + swpToolBar.cy = 0; + } + + pswp->cy -= swpToolBar.cy; + + pswp->cx -= cxScrollBar; + + cnt = 0; + v = peer->Frame->Top; + while (v) { + cnt++; + v = v->Prev; + if (v == peer->Frame->Top) break; + } + + pswp->cy -= cnt * cyScrollBar; + //if (pswp->cy < 0) pswp->cy = 0; + + if (v) { + pswp->cx /= v->Peer->pmData->cxChar; + //if (pswp->cx < 8) pswp->cx = 8; + if (pswp->cx > MAXXSIZE) + pswp->cx = MAXXSIZE; + pswp->cx *= v->Peer->pmData->cxChar; + + pswp->cy /= v->Peer->pmData->cyChar; + //if (pswp->cy < cnt * 2) pswp->cy = cnt * 2; + if (pswp->cy > MAXYSIZE) + pswp->cy = MAXYSIZE; + pswp->cy *= v->Peer->pmData->cyChar; + } + + pswp->cy += cnt * cyScrollBar; + + pswp->cx += cxScrollBar; + pswp->cy += swpToolBar.cy; + CalcFrameSWP(hwnd, pswp, FALSE); + DosReleaseMutexSem(hmtxPMData); + } + } + break; + + case WM_QUERYFRAMECTLCOUNT: + { + SHORT sCount = SHORT1FROMMR(peer->oldFrameProc(hwnd, msg, mp1, mp2)); + GView *v; + + DosRequestMutexSem(hmtxPMData, SEM_INDEFINITE_WAIT); + v = peer->Frame->Top; + while (v) { + sCount += (SHORT)3; + v = v->Prev; + if (v == peer->Frame->Top) break; + } + if (ShowToolBar) + sCount++; + DosReleaseMutexSem(hmtxPMData); + return MRESULT(sCount - 1); + } + + case WM_FORMATFRAME: + { + SHORT sCount = SHORT1FROMMR(peer->oldFrameProc(hwnd, msg, mp1, mp2)); + PSWP pswp; + HWND Bhwnd; + GView *v; + int x, w, h, fl, y; + int ctl, cnt; + int Hy, H1, yPos; + HWND hwndToolBar = WinWindowFromID(hwnd, FID_MTOOLBAR); + SWP swpToolBar; + PRECTL prcl; + + pswp = (PSWP) mp1; + prcl = (PRECTL) mp2; + + DosRequestMutexSem(hmtxPMData, SEM_INDEFINITE_WAIT); + sCount--; + + cnt = 0; + v = peer->Frame->Top; + while (v) { + cnt++; + v = v->Prev; + if (v == peer->Frame->Top) break; + } + + if (cnt == 0) { + DosReleaseMutexSem(hmtxPMData); + return MRFROMSHORT(sCount); + } + + fl = pswp[sCount].fl; + x = pswp[sCount].x; + y = pswp[sCount].y; + w = pswp[sCount].cx; + h = pswp[sCount].cy; + Bhwnd = pswp[sCount].hwndInsertBehind; + + if (ShowToolBar) { + swpToolBar = pswp[sCount]; + WinSendMsg(hwndToolBar, + WM_ADJUSTWINDOWPOS, + MPFROMP(&swpToolBar), + MPARAM(0)); + + + pswp[sCount].hwndInsertBehind = Bhwnd; + Bhwnd = pswp[sCount].hwnd = hwndToolBar; + pswp[sCount].fl = fl; + pswp[sCount].x = cxBorder; + pswp[sCount].cx = w; + + if (ShowToolBar == 1) { + pswp[sCount].y = y + h - swpToolBar.cy; + pswp[sCount].cy = swpToolBar.cy; + + h -= swpToolBar.cy; + if (prcl) + prcl->yTop -= swpToolBar.cy; + } else if (ShowToolBar == 2) { + pswp[sCount].y = y; + pswp[sCount].cy = swpToolBar.cy; + + y += swpToolBar.cy; + h -= swpToolBar.cy; + if (prcl) + prcl->yBottom += swpToolBar.cy; + } + sCount++; + } + + ctl = 0; + v = peer->Frame->Top; + + H1 = (h - cyScrollBar * cnt) / cnt; + H1 /= v->Peer->pmData->cyChar; + H1 *= v->Peer->pmData->cyChar; + + yPos = 0; + + while (v) { + v = v->Prev; + if (ctl == cnt - 1) { + Hy = h - yPos - cyScrollBar; + Hy /= v->Peer->pmData->cyChar; + Hy *= v->Peer->pmData->cyChar; + } else { + Hy = H1; + } + + pswp[sCount].fl = fl; + pswp[sCount].hwndInsertBehind = Bhwnd; + Bhwnd = pswp[sCount].hwnd = v->Peer->hwndView; + pswp[sCount].x = x; + pswp[sCount].cx = w - cxScrollBar; + pswp[sCount].y = yPos + y + cyScrollBar; + pswp[sCount].cy = Hy; + + sCount++; + + pswp[sCount].fl = fl; + pswp[sCount].hwndInsertBehind = Bhwnd; + Bhwnd = pswp[sCount].hwnd = v->Peer->hwndHscroll; + pswp[sCount].x = x; + pswp[sCount].cx = w - cxScrollBar; + pswp[sCount].y = yPos + y; + pswp[sCount].cy = cyScrollBar; + + yPos += cyScrollBar; + + sCount++; + + pswp[sCount].fl = fl; + pswp[sCount].hwndInsertBehind = Bhwnd; + Bhwnd = pswp[sCount].hwnd = v->Peer->hwndVscroll; + pswp[sCount].x = x + w - cxScrollBar; + pswp[sCount].cx = cxScrollBar; + pswp[sCount].y = yPos - cyScrollBar + y; + pswp[sCount].cy = Hy + cyScrollBar; + + yPos += Hy; + + sCount++; + + ctl++; + if (v == peer->Frame->Top) break; + } + DosReleaseMutexSem(hmtxPMData); + return MRFROMSHORT(sCount); + } + } + return peer->oldFrameProc(hwnd, msg, mp1, mp2); +} + +/*MRESULT EXPENTRY SizerWndProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2) { + switch (msg) { + case WM_CREATE: + break; + case WM_DESTROY: + break; + + case WM_BUTTON1DOWN: + case WM_BUTTON1UP: + case WM_MOUSEMOVE: + break; + + case WM_PAINT: + { + SWP swp; + HPS hps; + RECTL rc; + POINTL pt; + + + WinQueryWindowPos(hwnd, &swp); + hps = WinBeginPaint(hwnd, (HPS)NULL, &rc); + GpiSetColor(hps, CLR_GRAY); + GpiSetBackColor(hps, CLR_PALEGRAY); + if (swp.cy > 2 && swp.cx > 2) { + ptl.x = 1; + ptl.y = 1; + GpiMove(hps, &ptl); + ptl.x += swp.cx - 2; + ptl.y += swp.cy - 2; + GpiBox(hps, DRO_FILL, &ptl, 0, 0); + } + GpiSetColor(hps, CLR_WHITE); + ptl.x = 0; + ptl.y = 0; + GpiMove(hps, &ptl); + ptl.y += swp.cy; + GpiLine(hps, &ptl); + ptl.x += swp.cx; + GpiLine(hps, &ptl); + GpiSetColor(hps, CLR_GRAY); + ptl.y = 0; + GpiLine(hps, &ptl); + ptl.x = 0; + GpiLine(hps, &ptl); + + WinEndPaint(hps); + } + break; + } + return WinDefWndProc(hwnd, msg, mp1, mp2); +} +*/ +MRESULT EXPENTRY AVIOWndProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2) { + PMPTR *ptr = 0; + PMData *pmData = (PMData *)WinQueryWindowULong(hwnd, QWL_USER); + BYTE bBlank[2] = " "; + SHORT cxClient, cyClient; + HDC hdc; + SIZEL sizl; + PDRAGINFO pDragInfo; + PDRAGITEM pDragItem; + + switch (msg) { + case WM_CREATE: + ptr = (PMPTR *)mp1; + pmData = ptr ? (PMData *)ptr->p : 0; + assert(pmData != 0); + assert(WinSetWindowULong(hwnd, QWL_USER, (ULONG)pmData) == TRUE); + + hdc = WinOpenWindowDC(hwnd); + VioCreatePS(&pmData->hvps, MAXYSIZE, MAXXSIZE, 0, 1, 0); + sizl.cx = sizl.cy = 0; + pmData->hps = GpiCreatePS(hab, hdc, &sizl, + PU_PELS | GPIF_DEFAULT | GPIT_MICRO | GPIA_ASSOC); + VioAssociate(hdc, pmData->hvps); + if (WindowFont[0] != 0) { + int x, y; + + if (sscanf(WindowFont, "%dx%d", &x, &y) == 2) + VioSetDeviceCellSize((SHORT)y, (SHORT)x, pmData->hvps); + } + VioGetDeviceCellSize(&pmData->cyChar, &pmData->cxChar, pmData->hvps); + bBlank[1] = hcPlain_Background; + VioScrollUp(0, 0, -1, -1, -1, bBlank, pmData->hvps); + return 0; + + case WM_DESTROY: + VioAssociate(NULLHANDLE, pmData->hvps); + VioDestroyPS(pmData->hvps); + GpiDestroyPS(pmData->hps); + pmData->Peer->pmData = 0; + return 0; + + case UWM_DESTROY: + { + GViewPeer *Peer = pmData->Peer; + WinDestroyWindow(Peer->hwndVscroll); + WinDestroyWindow(Peer->hwndHscroll); + WinDestroyWindow(Peer->hwndView); + } + return 0; + + case WM_ERASEBACKGROUND: + return (MRESULT) FALSE; + + case WM_CLOSE: + if (WinPostMsg(pmData->hwndWorker, msg, mp1, mp2) == FALSE) { + WinMessageBox(HWND_DESKTOP, HWND_DESKTOP, + "WinPostMsg failed, WM_CLOSE", "FTE/PM", + 0, MB_OK | MB_ERROR | MB_APPLMODAL | MB_MOVEABLE); + } + return (MRESULT) FALSE; + + case WM_SIZE: + DosRequestMutexSem(hmtxPMData, SEM_INDEFINITE_WAIT); + { + GViewPeer *Peer = pmData->Peer; + + cxClient = SHORT1FROMMP(mp2); + cyClient = SHORT2FROMMP(mp2); + WinDefAVioWindowProc(hwnd, (USHORT)msg, (ULONG)mp1, (ULONG)mp2); + + if (cxClient <= pmData->cxChar || cyClient <= pmData->cyChar || reportSize == 0) { + DosReleaseMutexSem(hmtxPMData); + break; + } + + Peer->wW = cxClient / pmData->cxChar; + Peer->wH = cyClient / pmData->cyChar; + if (hwnd == WinQueryFocus(HWND_DESKTOP)) { + WinDestroyCursor(hwnd); + WinCreateCursor(hwnd, + pmData->cxChar * Peer->cX, + pmData->cyChar * (Peer->wH - Peer->cY - 1) + + pmData->cyChar * (100 - Peer->cEnd) / 100, + pmData->cxChar, pmData->cyChar * (Peer->cEnd - Peer->cStart) / 100, + CURSOR_TYPE, + NULL); + WinShowCursor(hwnd, TRUE); + } + //DosBeep(500, 100); + if (WinPostMsg(pmData->hwndWorker, msg, mp1, mp2) == FALSE) { + WinMessageBox(HWND_DESKTOP, HWND_DESKTOP, + "WinPostMsg failed, WM_SIZE", "FTE/PM", + 0, MB_OK | MB_ERROR | MB_APPLMODAL | MB_MOVEABLE); + } + } + DosReleaseMutexSem(hmtxPMData); + break; + + case WM_ACTIVATE: + case WM_SETSELECTION: + if (WinPostMsg(pmData->hwndWorker, msg, mp1, mp2) == FALSE) { + WinMessageBox(HWND_DESKTOP, HWND_DESKTOP, + "WinPostMsg failed, WM_SETFOCUS", "FTE/PM", + 0, MB_OK | MB_ERROR | MB_APPLMODAL | MB_MOVEABLE); + } + break; + + case WM_SETFOCUS: + DosRequestMutexSem(hmtxPMData, SEM_INDEFINITE_WAIT); + { + GViewPeer *Peer = pmData->Peer; + + if (SHORT1FROMMP(mp2)) { + WinCreateCursor(hwnd, + pmData->cxChar * Peer->cX, + pmData->cyChar * (Peer->wH - Peer->cY - 1) + + pmData->cyChar * (100 - Peer->cEnd) / 100, + pmData->cxChar, pmData->cyChar * (Peer->cEnd - Peer->cStart) / 100, + CURSOR_TYPE, + NULL); + WinShowCursor(hwnd, TRUE); + Peer->wState |= sfFocus; + } else { + WinDestroyCursor(hwnd); + Peer->wState &= ~sfFocus; + } + } + DosReleaseMutexSem(hmtxPMData); + if (WinPostMsg(pmData->hwndWorker, msg, mp1, mp2) == FALSE) { + WinMessageBox(HWND_DESKTOP, HWND_DESKTOP, + "WinPostMsg failed, WM_SETFOCUS", "FTE/PM", + 0, MB_OK | MB_ERROR | MB_APPLMODAL | MB_MOVEABLE); + } + break; + + case WM_VSCROLL: + if (WinPostMsg(pmData->hwndWorker, msg, mp1, mp2) == FALSE) { + WinMessageBox(HWND_DESKTOP, HWND_DESKTOP, + "WinPostMsg failed, WM_VSCROLL", "ftePM", + 0, MB_OK | MB_ERROR | MB_APPLMODAL | MB_MOVEABLE); + } + return 0; + + case WM_HSCROLL: + if (WinPostMsg(pmData->hwndWorker, msg, mp1, mp2) == FALSE) { + WinMessageBox(HWND_DESKTOP, HWND_DESKTOP, + "WinPostMsg failed, WM_HSCROLL", "ftePM", + 0, MB_OK | MB_ERROR | MB_APPLMODAL | MB_MOVEABLE); + } + return 0; + + case WM_COMMAND: + if (SHORT1FROMMP(mp1) >= 8192) { + if (WinPostMsg(pmData->hwndWorker, msg, mp1, mp2) == FALSE) { + WinMessageBox(HWND_DESKTOP, HWND_DESKTOP, + "WinPostMsg failed, WM_COMMAND", "ftePM", + 0, MB_OK | MB_ERROR | MB_APPLMODAL | MB_MOVEABLE); + } + } + break; + + case WM_CHAR: + if (WinPostMsg(pmData->hwndWorker, msg, mp1, mp2) == FALSE) { + WinMessageBox(HWND_DESKTOP, HWND_DESKTOP, + "WinPostMsg failed, WM_CHAR", "ftePM", + 0, MB_OK | MB_ERROR | MB_APPLMODAL | MB_MOVEABLE); + } + return (MRESULT) TRUE; + + case WM_MOUSEMOVE: + { + long b; + b = 0; + if (WinGetKeyState(HWND_DESKTOP, VK_BUTTON1) & 0x8000) + b |= 1; + if (WinGetKeyState(HWND_DESKTOP, VK_BUTTON2) & 0x8000) + b |= 2; + if (WinGetKeyState(HWND_DESKTOP, VK_BUTTON3) & 0x8000) + b |= 4; + if (b == 0) + break; + } + case WM_BUTTON1DOWN: + case WM_BUTTON1DBLCLK: + case WM_BUTTON1UP: + case WM_BUTTON2DOWN: + case WM_BUTTON2DBLCLK: + case WM_BUTTON2UP: + case WM_BUTTON3DOWN: + case WM_BUTTON3DBLCLK: + case WM_BUTTON3UP: + if (WinPostMsg(pmData->hwndWorker, msg, mp1, mp2) == FALSE) { + WinMessageBox(HWND_DESKTOP, HWND_DESKTOP, + "WinPostMsg failed, WM_MOUSE", "ftePM", + 0, MB_OK | MB_ERROR | MB_APPLMODAL | MB_MOVEABLE); + } + break; + + case WM_PAINT: + DosRequestMutexSem(hmtxPMData, SEM_INDEFINITE_WAIT); + { + GViewPeer *Peer = pmData->Peer; + + WinBeginPaint(hwnd, pmData->hps, NULL); + if (Peer->wH > 0 && Peer->wH <= MAXYSIZE && + Peer->wW > 0 && Peer->wW <= MAXXSIZE) + VioShowBuf(0, (SHORT)(MAXXSIZE * Peer->wH * 2), pmData->hvps); + WinEndPaint(pmData->hps); + } + DosReleaseMutexSem(hmtxPMData); + return 0; + + case DM_DRAGOVER: + { + char buf[1024] = ""; + pDragInfo = (PDRAGINFO) mp1; + DrgAccessDraginfo( pDragInfo ); + pDragItem = DrgQueryDragitemPtr( pDragInfo, 0 ); + + // Don't accept multi select and non-file + DrgQueryNativeRMF(pDragItem, sizeof(buf), buf); + + if (pDragInfo->cditem > 1 || strstr(buf, "DRM_OS2FILE") == 0) + return (MRFROM2SHORT((DOR_NEVERDROP), (DO_UNKNOWN))); + else + return (MRFROM2SHORT((DOR_DROP), (DO_UNKNOWN))); + } + + case DM_DROP: + { + pDragInfo = (PDRAGINFO)mp1; + DrgAccessDraginfo(pDragInfo); + pDragItem = DrgQueryDragitemPtr(pDragInfo, 0); + + DrgQueryStrName(pDragItem->hstrContainerName,100,dragname); + DrgQueryStrName(pDragItem->hstrSourceName,100,dragname+strlen(dragname)); + WinPostMsg(pmData->hwndWorker, UWM_DROPPEDFILE, 0, 0); + } + break; + } + return WinDefWindowProc(hwnd, msg, mp1, mp2); +} + +MRESULT EXPENTRY ObjectWndProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2) { + switch (msg) { + case WM_CREATE: + PMPTR *ptr = (PMPTR *)mp1; + GViewPeer *peer = ptr ? (GViewPeer *)ptr->p : 0; + assert(WinSetWindowULong(hwnd, QWL_USER, (ULONG)peer) == TRUE); + break; + } + return WinDefWindowProc(hwnd, msg, mp1, mp2); +} + +MRESULT EXPENTRY CreatorWndProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2) { + switch (msg) { + case UWM_CREATEWORKER: + { + GViewPeer *peer = (GViewPeer *)mp1; + PMData *pmData = (PMData *)mp2; + PMPTR ptr; + + ptr.len = sizeof(ptr); + ptr.p = peer; + + //DosBeep(2500, 1000); + + peer->hwndWorker = pmData->hwndWorker = + WinCreateWindow(HWND_OBJECT, + szObject, + "Worker", + 0, + 0, 0, 0, 0, + HWND_OBJECT, HWND_TOP, + 0, (void *)&ptr, NULL); + + assert(peer->hwndWorker != NULLHANDLE); + + return (MRESULT)TRUE; + } + + case UWM_CREATEFRAME: + { + GFramePeer *peer = (GFramePeer *)PVOIDFROMMP(mp1); + FRAMECDATA fcdata; + + fcdata.cb = sizeof(FRAMECDATA); + fcdata.flCreateFlags = flFrame; + fcdata.hmodResources = 0; + fcdata.idResources = 1; + + //DosBeep(2500, 1000); + + peer->hwndFrame = WinCreateWindow(HWND_DESKTOP, + WC_FRAME, NULL, 0, 0, 0, 0, 0, + hwndCreatorUser, HWND_TOP, 1, + &fcdata, NULL); + + assert(peer->hwndFrame != NULLHANDLE); + + WinSetWindowULong(peer->hwndFrame, QWL_USER, (ULONG)peer); + + peer->oldFrameProc = WinSubclassWindow(peer->hwndFrame, (PFNWP) FrameWndProc); + + if (ShowToolBar) { + peer->hwndToolBar = CreateToolBar(peer->hwndFrame, peer->hwndFrame, FID_MTOOLBAR); + assert(peer->hwndToolBar != NULLHANDLE); + } + + + return (MRESULT)TRUE; + } + + case UWM_CREATEMAINMENU: + { + GFramePeer *peer = (GFramePeer *)mp1; + char *Menu = (char *)PVOIDFROMMP(mp2); + HWND hwnd, hwndMenu; + char font[256]; + ULONG AttrFound = 0; + LONG len = -1; + + hwnd = WinWindowFromID(peer->hwndFrame, FID_MENU); + if (hwnd != NULLHANDLE) { + if (len == -1) { + AttrFound = 0; + len = WinQueryPresParam(hwnd, PP_FONTNAMESIZE, PP_FONTHANDLE, &AttrFound, sizeof(font), font, 0); + } + WinDestroyWindow(hwnd); + } + + hwndMenu = CreatePMMainMenu(peer->hwndFrame, peer->hwndFrame, Menu); + + if (len > 0) + WinSetPresParam(hwndMenu, AttrFound, len, font); + WinSendMsg(peer->hwndFrame, WM_UPDATEFRAME, MPFROMLONG(FCF_MENU), 0); + + return (MRESULT)hwndMenu; + } + + case UWM_CREATEPOPUPMENU: + { + GFramePeer *peer = (GFramePeer *)mp1; + int MenuId = LONGFROMMP(mp2); + + static HWND hwnd = 0; + POINTL ptl; + char font[256]; + ULONG AttrFound = 0; + ULONG len; + + if (hwnd != 0) { + WinDestroyWindow(hwnd); + hwnd = 0; + } + + hwnd = CreatePMMenu(HWND_DESKTOP, peer->hwndFrame, MenuId, 0, 0); + + WinQueryMsgPos(hab, &ptl); + + len = WinQueryPresParam(peer->menuBar, PP_FONTNAMESIZE, PP_FONTHANDLE, &AttrFound, sizeof(font), font, 0); + if (len > 0) + WinSetPresParam(hwnd, AttrFound, len, font); + + WinPopupMenu(HWND_DESKTOP, peer->Frame->Active->Peer->hwndView, hwnd, + ptl.x, ptl.y, + 0, + PU_HCONSTRAIN | PU_VCONSTRAIN | + PU_NONE | PU_KEYBOARD | + PU_MOUSEBUTTON1 | PU_MOUSEBUTTON2 | PU_MOUSEBUTTON3); + + return (MRESULT)TRUE; + } + } + return WinDefWindowProc(hwnd, msg, mp1, mp2); +} + +int ConGetEvent(TEventMask EventMask, TEvent *Event, int WaitTime, int Delete, GView **view) { + QMSG qmsg; + GFrame *f; + GView *v; + + if (view) + *view = 0; + + if (EventBuf.What != evNone) { + *Event = EventBuf; + if (Delete) EventBuf.What = evNone; + return 0; + } + EventBuf.What = evNone; + Event->What = evNone; + + //DosBeep(800, 10); + + if (WaitTime != -1) { + if (WinPeekMsg(hab, &qmsg, NULLHANDLE, 0, 0, PM_NOREMOVE) == FALSE) + return 0; + } + if (WinGetMsg(hab, &qmsg, NULLHANDLE, 0, 0) == FALSE) + return -1; + + //DosBeep(800, 10); + + f = frames; + while (f) { + v = f->Top; + while (frames && v) { + if (v->Peer->hwndWorker == qmsg.hwnd) { + if (FocusCapture && v != FocusCapture) { + WinSetFocus(HWND_DESKTOP, FocusCapture->Peer->hwndView); + frames = f; + break; + } + if (view) + *view = v; + switch (qmsg.msg) { + /*case WM_ACTIVATE: + case WM_SETSELECTION: + if (SHORT1FROMMP(qmsg.mp1) == TRUE) { + if (!v->IsActive()) + v->Parent->SelectView(v); + DosBeep(800, 10); + return 0; + } + break;*/ + case WM_SETFOCUS: + if (SHORT1FROMMP(qmsg.mp2) == TRUE) { + if (!v->IsActive()) + v->Parent->SelectView(v); + //DosBeep(800, 10); + return 0; + } + break; + + case UWM_NOTIFY: + //DosBeep(200, 200); + Event->What = evNotify; + Event->Msg.View = v; + Event->Msg.Model = (EModel *)qmsg.mp1; + Event->Msg.Command = cmPipeRead; + Event->Msg.Param1 = (long)qmsg.mp2; + frames = f; + return 0; + + case UWM_DROPPEDFILE: + if (!v->IsActive()) + v->Parent->SelectView(v); + Event->What = evCommand; + Event->Msg.View = v; + Event->Msg.Command = cmDroppedFile; + Event->Msg.Param1 = 0; + Event->Msg.Param2 = &dragname; + frames = f; + return 0; + + case WM_SIZE: + frames = f; + //DosBeep(500, 500); + v->Resize(v->Peer->wW, v->Peer->wH); + return 0; + + case WM_VSCROLL: + //DosBeep(200, 2000); + if (!v->IsActive()) + v->Parent->SelectView(v); + Event->What = evNone; + Event->Msg.View = v; + Event->Msg.Param1 = 0; + Event->Msg.Param2 = 0; + switch (SHORT2FROMMP(qmsg.mp2)) { + case SB_LINEUP: + Event->What = evCommand; + Event->Msg.Command = cmVScrollUp; + break; + + case SB_LINEDOWN: + Event->What = evCommand; + Event->Msg.Command = cmVScrollDown; + break; + + case SB_PAGEUP: + Event->What = evCommand; + Event->Msg.Command = cmVScrollPgUp; + break; + + case SB_PAGEDOWN: + Event->What = evCommand; + Event->Msg.Command = cmVScrollPgDn; + break; + + case SB_ENDSCROLL: + WinSetFocus(HWND_DESKTOP, v->Parent->Active->Peer->hwndView); + /* no break */ + case SB_SLIDERPOSITION: + case SB_SLIDERTRACK: + { + SHORT x = SHORT1FROMMP(qmsg.mp2); + + if (x != 0) { + Event->What = evCommand; + Event->Msg.Command = cmVScrollMove; + if (v->Peer->sbVtotal > 32000) + Event->Msg.Param1 = (x - 1) * v->Peer->sbVtotal / 32000; + else + Event->Msg.Param1 = x - 1; + } + } + break; + } + return 0; + + case WM_HSCROLL: + //DosBeep(800, 2000); + if (!v->IsActive()) + v->Parent->SelectView(v); + Event->What = evNone; + Event->Msg.View = v; + Event->Msg.Param1 = 0; + Event->Msg.Param2 = 0; + switch (SHORT2FROMMP(qmsg.mp2)) { + case SB_LINEUP: + Event->What = evCommand; + Event->Msg.Command = cmHScrollLeft; + break; + + case SB_LINEDOWN: + Event->What = evCommand; + Event->Msg.Command = cmHScrollRight; + break; + + case SB_PAGEUP: + Event->What = evCommand; + Event->Msg.Command = cmHScrollPgLt; + break; + + case SB_PAGEDOWN: + Event->What = evCommand; + Event->Msg.Command = cmHScrollPgRt; + break; + + case SB_ENDSCROLL: + WinSetFocus(HWND_DESKTOP, v->Parent->Active->Peer->hwndView); + /* no break */ + case SB_SLIDERPOSITION: + case SB_SLIDERTRACK: + { + SHORT x = SHORT1FROMMP(qmsg.mp2); + + if (x != 0) { + Event->What = evCommand; + Event->Msg.Command = cmHScrollMove; + if (v->Peer->sbHtotal > 32000) + Event->Msg.Param1 = (x - 1) * v->Peer->sbHtotal / 32000; + else + Event->Msg.Param1 = x - 1; + } + } + break; + } + return 0; + + case WM_CLOSE: + //DosBeep(500, 1500); + frames = f; + Event->What = evCommand; + Event->Msg.View = v->Parent->Active; + Event->Msg.Command = cmClose; + return 0; + + case WM_COMMAND: + //DosBeep(50, 2500); + if (SHORT1FROMMP(qmsg.mp1) >= 8192) { + Event->What = evCommand; + Event->Msg.View = v->Parent->Active; + Event->Msg.Command = (SHORT1FROMMP(qmsg.mp1) - 8192) + 65536; + frames = f; + return 0; + } + break; + + case WM_CHAR: + //DosBeep(50, 500); + Event->What = evNone; + Event->Msg.View = v; + ConvertKey(SHORT1FROMMP(qmsg.mp2), /* char */ + SHORT2FROMMP(qmsg.mp2), /* virtual */ + SHORT1FROMMP(qmsg.mp1), /* flags */ + CHAR4FROMMP(qmsg.mp1), /* scan */ + *Event); + frames = f; + return 0; + + case WM_BUTTON1DOWN: + case WM_BUTTON2DOWN: + case WM_BUTTON3DOWN: + case WM_BUTTON1DBLCLK: + case WM_BUTTON2DBLCLK: + case WM_BUTTON3DBLCLK: + if (!v->IsActive()) + v->Parent->SelectView(v); + case WM_BUTTON1UP: + case WM_BUTTON2UP: + case WM_BUTTON3UP: + case WM_MOUSEMOVE: + Event->Mouse.What = evNone; + Event->Msg.View = v; + Event->Mouse.X = ((SHORT)SHORT1FROMMP(qmsg.mp1)) / v->Peer->pmData->cxChar; + Event->Mouse.Y = v->Peer->wH - ((SHORT)SHORT2FROMMP(qmsg.mp1)) / v->Peer->pmData->cyChar - 1; + Event->Mouse.Buttons = 1; + Event->Mouse.Count = 1; + Event->Mouse.KeyMask = 0; + if (WinGetKeyState(HWND_DESKTOP, VK_CTRL) & 0x8000) + Event->Mouse.KeyMask |= kfCtrl; + if (WinGetKeyState(HWND_DESKTOP, VK_ALT) & 0x8000) + Event->Mouse.KeyMask |= kfAlt; + if (WinGetKeyState(HWND_DESKTOP, VK_SHIFT) & 0x8000) + Event->Mouse.KeyMask |= kfShift; +// printf("KeyFlags: %d\n", Event->Mouse.KeyMask); + //DosBeep(2000, 50); + frames = f; + + switch (qmsg.msg) { + case WM_BUTTON1DOWN: + Event->What = evMouseDown; + v->Peer->OldMouseX = Event->Mouse.X; + v->Peer->OldMouseY = Event->Mouse.Y; + return 0; + + case WM_BUTTON1DBLCLK: + Event->What = evMouseDown; + Event->Mouse.Count = 2; + v->Peer->OldMouseX = Event->Mouse.X; + v->Peer->OldMouseY = Event->Mouse.Y; + return 0; + + case WM_BUTTON1UP: + Event->What = evMouseUp; + v->Peer->OldMouseX = Event->Mouse.X; + v->Peer->OldMouseY = Event->Mouse.Y; + return 0; + + case WM_BUTTON2DOWN: + Event->What = evMouseDown; + Event->Mouse.Buttons = 2; + v->Peer->OldMouseX = Event->Mouse.X; + v->Peer->OldMouseY = Event->Mouse.Y; + return 0; + + case WM_BUTTON2DBLCLK: + Event->What = evMouseDown; + Event->Mouse.Buttons = 2; + Event->Mouse.Count = 2; + v->Peer->OldMouseX = Event->Mouse.X; + v->Peer->OldMouseY = Event->Mouse.Y; + return 0; + + case WM_BUTTON2UP: + Event->What = evMouseUp; + Event->Mouse.Buttons = 2; + v->Peer->OldMouseX = Event->Mouse.X; + v->Peer->OldMouseY = Event->Mouse.Y; + return 0; + + case WM_BUTTON3DOWN: + Event->What = evMouseDown; + Event->Mouse.Buttons = 4; + v->Peer->OldMouseX = Event->Mouse.X; + v->Peer->OldMouseY = Event->Mouse.Y; + return 0; + + case WM_BUTTON3DBLCLK: + Event->What = evMouseDown; + Event->Mouse.Buttons = 4; + Event->Mouse.Count = 2; + v->Peer->OldMouseX = Event->Mouse.X; + v->Peer->OldMouseY = Event->Mouse.Y; + return 0; + + case WM_BUTTON3UP: + Event->What = evMouseUp; + Event->Mouse.Buttons = 4; + v->Peer->OldMouseX = Event->Mouse.X; + v->Peer->OldMouseY = Event->Mouse.Y; + return 0; + + case WM_MOUSEMOVE: + Event->What = evMouseMove; + Event->Mouse.Buttons = 0; + if (WinGetKeyState(HWND_DESKTOP, VK_BUTTON1) & 0x8000) + Event->Mouse.Buttons |= 1; + if (WinGetKeyState(HWND_DESKTOP, VK_BUTTON2) & 0x8000) + Event->Mouse.Buttons |= 2; + if (WinGetKeyState(HWND_DESKTOP, VK_BUTTON3) & 0x8000) + Event->Mouse.Buttons |= 4; + + if (Event->Mouse.Buttons != 0) { + if (Event->Mouse.X != v->Peer->OldMouseX || + Event->Mouse.Y != v->Peer->OldMouseY) + { + v->Peer->OldMouseX = Event->Mouse.X; + v->Peer->OldMouseY = Event->Mouse.Y; + return 0; + } else if (Event->Mouse.X >= 0 && + Event->Mouse.Y >= 0 && + Event->Mouse.X < v->Peer->wW && + Event->Mouse.Y < v->Peer->wH) + { + Event->What = evNone; + } + } + } + break; + + default: + WinDispatchMsg(hab, &qmsg); + return 0; + } + } + v = v->Next; + if (v == f->Top) break; + } + f = f->Next; + if (f == frames) break; + } + WinDispatchMsg(hab, &qmsg); + return 0; +} + +static void _LNK_CONV WorkThread(void *) { + habW = WinInitialize(0); + hmqW = WinCreateMsgQueue(hab, 0); + + hwndCreatorWorker = WinCreateWindow(HWND_OBJECT, + szCreator, + "Creator", + 0, + 0, 0, 0, 0, + HWND_OBJECT, HWND_TOP, + 0, NULL, NULL); + + assert(hwndCreatorWorker != 0); + + // work thread started + DosPostEventSem(WorkerStarted); + + ULONG ulPostCount; + DosWaitEventSem(StartInterface, SEM_INDEFINITE_WAIT); + DosResetEventSem(StartInterface, &ulPostCount); + + //DosBeep(200, 200); + if (gui->Start(gui->fArgc, gui->fArgv) == 0) { + gui->doLoop = 1; + //DosBeep(500, 500); + while (gui->doLoop) + gui->ProcessEvent(); + + gui->Stop(); + } + + WinDestroyMsgQueue(hmqW); + WinTerminate(habW); + //DosBeep(500, 500); + WinPostQueueMsg(hmq, WM_QUIT, 0, 0); + _endthread(); +} + +/////////////////////////////////////////////////////////////////////////// + +GViewPeer::GViewPeer(GView *view, int XSize, int YSize) { + HWND parent; + + View = view; +// wX = 0; +// wY = 0; + wW = XSize; + wH = YSize; + sbVtotal = 0; + sbVstart = 0; + sbVamount = 0; + sbHtotal = 0; + sbHstart = 0; + sbHamount = 0; + wState = 0; + cVisible = 1; + cStart = 0; // % + cEnd = 100; + OldMouseX = OldMouseY = 0xFFFF; + + pmData = (PMData *)malloc(sizeof(PMData)); + + pmData->Peer = this; + pmData->hvps = 0; + pmData->cxChar = 8; + pmData->cyChar = 14; + pmData->hwndWorker = 0; + + parent = View->Parent->Peer->hwndFrame; + + WinSendMsg(hwndCreatorWorker, UWM_CREATEWORKER, MPFROMP(this), MPFROMP(pmData)); + + WinSendMsg(parent, UWM_CREATECHILD, MPFROMP(this), MPFROMP(pmData)); +} + +GViewPeer::~GViewPeer() { + WinSendMsg(hwndView, UWM_DESTROY, 0, 0); + WinDestroyWindow(hwndWorker); + free(pmData); +} + +int GViewPeer::ConPutBox(int X, int Y, int W, int H, PCell Cell) { + int I; + char *p = (char *) Cell; + int Hidden = 0; + + DosRequestMutexSem(hmtxPMData, SEM_INDEFINITE_WAIT); + if (Y < 0 || Y >= wH || X < 0 || X >= wW || + Y + H < 0 || Y + H > wH || X + W < 0 || X + W > wW) + { + //fprintf(stderr, + // "X:%d, Y:%d, W:%d, H:%d, wW:%d, wH:%d\n", + // X, Y, W, H, wW, wH); + DosReleaseMutexSem(hmtxPMData); + return -1; + } + for (I = 0; I < H; I++) { + if (I + Y == cY) + Hidden = PMHideCursor(); + VioWrtCellStr(p, (USHORT)(W << 1), (USHORT)(Y + I), (USHORT)X, pmData->hvps); + if (Hidden) + PMShowCursor(); + p += W << 1; + } + DosReleaseMutexSem(hmtxPMData); + return 0; +} + +int GViewPeer::ConGetBox(int X, int Y, int W, int H, PCell Cell) { + int I; + USHORT WW = (USHORT)(W << 1); + char *p = (char *) Cell; + + DosRequestMutexSem(hmtxPMData, SEM_INDEFINITE_WAIT); + if (Y < 0 || Y >= wH || X < 0 || X >= wW || + Y + H < 0 || Y + H > wH || X + W < 0 || X + W > wW) + { + //fprintf(stderr, + // "X:%d, Y:%d, W:%d, H:%d, wW:%d, wH:%d\n", + // X, Y, W, H, wW, wH); + DosReleaseMutexSem(hmtxPMData); + return -1; + } + for (I = 0; I < H; I++) { + VioReadCellStr((char *)p, &WW, (USHORT)(Y + I), (USHORT)X, pmData->hvps); + p += W << 1; + } + DosReleaseMutexSem(hmtxPMData); + return 0; +} + +int GViewPeer::ConPutLine(int X, int Y, int W, int H, PCell Cell) { + int I; + char *p = (char *) Cell; + int Hidden = 0; + + DosRequestMutexSem(hmtxPMData, SEM_INDEFINITE_WAIT); + if (Y < 0 || Y >= wH || X < 0 || X >= wW || + Y + H < 0 || Y + H > wH || X + W < 0 || X + W > wW) + { + //fprintf(stderr, + // "X:%d, Y:%d, W:%d, H:%d, wW:%d, wH:%d\n", + // X, Y, W, H, wW, wH); + DosReleaseMutexSem(hmtxPMData); + return -1; + } + for (I = 0; I < H; I++) { + if (I + Y == cY) + Hidden = PMHideCursor(); + VioWrtCellStr(p, (USHORT)(W << 1), (USHORT)(Y + I), (USHORT)X, pmData->hvps); + if (Hidden) + PMShowCursor(); + } + DosReleaseMutexSem(hmtxPMData); + return 0; +} + +int GViewPeer::ConSetBox(int X, int Y, int W, int H, TCell Cell) { + int I; + char *p = (char *) &Cell; + int Hidden = 0; + + DosRequestMutexSem(hmtxPMData, SEM_INDEFINITE_WAIT); + if (Y < 0 || Y >= wH || X < 0 || X >= wW || + Y + H < 0 || Y + H > wH || X + W < 0 || X + W > wW) + { + //fprintf(stderr, + // "X:%d, Y:%d, W:%d, H:%d, wW:%d, wH:%d\n", + // X, Y, W, H, wW, wH); + DosReleaseMutexSem(hmtxPMData); + return -1; + } + for (I = 0; I < H; I++) { + if (I + Y == cY) + Hidden = PMHideCursor(); + VioWrtNCell(p, (USHORT)(W), (USHORT)(Y + I), (USHORT)X, pmData->hvps); + if (Hidden) + PMShowCursor(); + } + DosReleaseMutexSem(hmtxPMData); + return 0; +} + +int GViewPeer::ConScroll(int Way, int X, int Y, int W, int H, TAttr Fill, int Count) { + TCell FillCell = (TCell)(Fill << 8); + int Hidden = 0; + + DosRequestMutexSem(hmtxPMData, SEM_INDEFINITE_WAIT); + if (Y < 0 || Y >= wH || X < 0 || X >= wW || + Y + H < 0 || Y + H > wH || X + W < 0 || X + W > wW) + { + //fprintf(stderr, + // "X:%d, Y:%d, W:%d, H:%d, wW:%d, wH:%d\n", + // X, Y, W, H, wW, wH); + DosReleaseMutexSem(hmtxPMData); + return -1; + } + Hidden = PMHideCursor(); + switch (Way) { + case csUp: + VioScrollUp((USHORT)Y, (USHORT)X, (USHORT)(Y + H - 1), (USHORT)(X + W - 1), (USHORT)Count, (PBYTE)&FillCell, pmData->hvps); + break; + case csDown: + VioScrollDn((USHORT)Y, (USHORT)X, (USHORT)(Y + H - 1), (USHORT)(X + W - 1), (USHORT)Count, (PBYTE)&FillCell, pmData->hvps); + break; + case csLeft: + VioScrollLf((USHORT)Y, (USHORT)X, (USHORT)(Y + H - 1), (USHORT)(X + W - 1), (USHORT)Count, (PBYTE)&FillCell, pmData->hvps); + break; + case csRight: + VioScrollRt((USHORT)Y, (USHORT)X, (USHORT)(Y + H - 1), (USHORT)(X + W - 1), (USHORT)Count, (PBYTE)&FillCell, pmData->hvps); + break; + } + if (Hidden) + PMShowCursor(); + DosReleaseMutexSem(hmtxPMData); + return 0; +} + +int GViewPeer::ConSetSize(int X, int Y) { + wW = X; + wH = Y; + return 1; +} + +int GViewPeer::ConQuerySize(int *X, int *Y) { + if (X) *X = wW; + if (Y) *Y = wH; + return 1; +} + +int GViewPeer::ConSetCursorPos(int X, int Y) { + if (X < 0) X = 0; + if (X >= wW) X = wW - 1; + if (Y < 0) Y = 0; + if (Y >= wH) Y = wH - 1; + cX = X; + cY = Y; + if (wState & sfFocus) + return PMSetCursorPos(); + else + return 1; +} + +int GViewPeer::ConQueryCursorPos(int *X, int *Y) { + if (X) *X = cX; + if (Y) *Y = cY; + return 1; +} + +int GViewPeer::ConShowCursor() { + cVisible = 1; + if (wState & sfFocus) + return PMShowCursor(); + else + return 1; +} + +int GViewPeer::ConHideCursor() { + cVisible = 0; + if (wState & sfFocus) + return PMHideCursor(); + else + return 1; +} + +int GViewPeer::ConCursorVisible() { + return cVisible; +} + +int GViewPeer::ConSetCursorSize(int Start, int End) { + cStart = Start; + cEnd = End; + if (wState & sfFocus) + return PMSetCursorPos(); + else + return 1; +} + +int GViewPeer::ExpandHeight(int DeltaY) { + if (View->Parent->Top == View->Next) + return -1; + if (DeltaY + wH < 3) + return -1; + if (View->Next->Peer->wH - DeltaY < 3) + return -1; + ConSetSize(wW, wH + DeltaY); + //View->Next->Peer->wY += DeltaY; + View->Next->ConSetSize(View->Next->Peer->wW, View->Next->Peer->wH - DeltaY); + View->Parent->Peer->SizeFrame(); + return 0; +} + +int GViewPeer::QuerySbVPos() { + return sbVstart; +} + +int GViewPeer::SetSbVPos(int Start, int Amount, int Total) { + if (sbVstart != Start || + sbVamount != Amount || + sbVtotal != Total) + { + sbVstart = Start; + sbVamount = Amount; + sbVtotal = Total; + + if (View->Parent == 0) + return 0; + + WinEnableWindowUpdate(hwndVscroll, FALSE); + if (sbVamount < sbVtotal) { + if (sbVtotal > 32000) { + int total = 32000; + int start = total * sbVstart / sbVtotal; + int amount = total * sbVamount / sbVtotal; + + WinSendMsg(hwndVscroll, SBM_SETTHUMBSIZE, + (MPFROM2SHORT((amount), (total))), 0); + WinSendMsg(hwndVscroll, SBM_SETSCROLLBAR, + (MPFROMSHORT((start + 1))), + (MPFROM2SHORT((1), (total - amount + 2)))); + } else { + WinSendMsg(hwndVscroll, SBM_SETTHUMBSIZE, + (MPFROM2SHORT((sbVamount), (sbVtotal))), 0); + WinSendMsg(hwndVscroll, SBM_SETSCROLLBAR, + (MPFROMSHORT((sbVstart + 1))), + (MPFROM2SHORT((1), (sbVtotal - sbVamount + 2)))); + } + } else { + WinSendMsg(hwndVscroll, SBM_SETTHUMBSIZE, + MPFROM2SHORT(0, 0), 0); + WinSendMsg(hwndVscroll, SBM_SETSCROLLBAR, + MPFROMSHORT(0), + MPFROM2SHORT(0, 0)); + } + WinEnableWindowUpdate(hwndVscroll, TRUE); + } + return 1; +} + +int GViewPeer::SetSbHPos(int Start, int Amount, int Total) { + if (sbHstart != Start || + sbHamount != Amount || + sbHtotal != Total) + { + sbHstart = Start; + sbHamount = Amount; + sbHtotal = Total; + + if (View->Parent == 0) + return 0; + + WinEnableWindowUpdate(hwndHscroll, FALSE); + if (sbHtotal > sbHamount) { + if (sbHtotal > 32000) { + int total = 32000; + int start = total * sbVstart / sbVtotal; + int amount = total * sbVamount / sbVtotal; + + WinSendMsg(hwndHscroll, SBM_SETTHUMBSIZE, + (MPFROM2SHORT(amount, total)), 0); + WinSendMsg(hwndHscroll, SBM_SETSCROLLBAR, + (MPFROMSHORT(start + 1)), + (MPFROM2SHORT(1, total - amount + 2))); + } else { + WinSendMsg(hwndHscroll, SBM_SETTHUMBSIZE, + (MPFROM2SHORT(sbHamount, sbHtotal)), 0); + WinSendMsg(hwndHscroll, SBM_SETSCROLLBAR, + (MPFROMSHORT(sbHstart + 1)), + (MPFROM2SHORT(1, sbHtotal - sbHamount + 2))); + } + } else { + WinSendMsg(hwndHscroll, SBM_SETTHUMBSIZE, + (MPFROM2SHORT(0, 0)), 0); + WinSendMsg(hwndHscroll, SBM_SETSCROLLBAR, + (MPFROMSHORT(0)), + (MPFROM2SHORT(0, 0))); + } + WinEnableWindowUpdate(hwndHscroll, TRUE); + } + return 1; +} + +int GViewPeer::UpdateCursor() { + ConSetCursorPos(cX, cY); + ConSetCursorSize(cStart, cEnd); + if (cVisible) + ConShowCursor(); + else + ConHideCursor(); + return 1; +} + +int GViewPeer::PMShowCursor() { + if (wState & sfFocus) + WinShowCursor(hwndView, TRUE); + return 1; +} + +int GViewPeer::PMHideCursor() { + if (wState & sfFocus) + WinShowCursor(hwndView, FALSE); + return 1; +} + +int GViewPeer::PMSetCursorPos() { + if (wState & sfFocus) { + WinDestroyCursor(hwndView); + WinCreateCursor(hwndView, + pmData->cxChar * cX, + pmData->cyChar * (wH - cY - 1) + + pmData->cyChar * (100 - cEnd) / 100, + pmData->cxChar, pmData->cyChar * (cEnd - cStart) / 100, + CURSOR_TYPE, + NULL); + WinShowCursor(hwndView, TRUE); + } + return 1; +} + +/////////////////////////////////////////////////////////////////////////// + +GView::GView(GFrame *parent, int XSize, int YSize) { + Parent = parent; + Prev = Next = 0; + Peer = new GViewPeer(this, XSize, YSize); + if (Parent) + Parent->AddView(this); +} + +GView::~GView() { + if (FocusCapture == this) + CaptureFocus(0); + if (MouseCapture == this) + CaptureMouse(0); + if (Parent) + Parent->RemoveView(this); + if (Peer) { + Peer->View = 0; + delete Peer; + Peer = 0; + } +} + +int GView::ConClear() { + int W, H; + TDrawBuffer B; + + ConQuerySize(&W, &H); + MoveChar(B, 0, W, ' ', 0x07, 1); + ConSetBox(0, 0, W, H, B[0]); + return 1; +} + +int GView::ConPutBox(int X, int Y, int W, int H, PCell Cell) { + return Peer->ConPutBox(X, Y, W, H, Cell); +} + +int GView::ConGetBox(int X, int Y, int W, int H, PCell Cell) { + return Peer->ConGetBox(X, Y, W, H, Cell); +} + +int GView::ConPutLine(int X, int Y, int W, int H, PCell Cell) { + return Peer->ConPutLine(X, Y, W, H, Cell); +} + +int GView::ConSetBox(int X, int Y, int W, int H, TCell Cell) { + return Peer->ConSetBox(X, Y, W, H, Cell); +} + +int GView::ConScroll(int Way, int X, int Y, int W, int H, TAttr Fill, int Count) { + return Peer->ConScroll(Way, X, Y, W, H, Fill, Count); +} + +int GView::ConSetSize(int X, int Y) { + if (Peer->ConSetSize(X, Y)) + Resize(X, Y); + else + return 0; + return 1; +} + +int GView::ConQuerySize(int *X, int *Y) { + return Peer->ConQuerySize(X, Y); +} + +int GView::ConSetCursorPos(int X, int Y) { + return Peer->ConSetCursorPos(X, Y); +} + +int GView::ConQueryCursorPos(int *X, int *Y) { + return Peer->ConQueryCursorPos(X, Y); +} + +int GView::ConShowCursor() { + return Peer->ConShowCursor(); +} + +int GView::ConHideCursor() { + return Peer->ConHideCursor(); +} + +int GView::ConCursorVisible() { + return Peer->ConCursorVisible(); +} + +int GView::ConSetCursorSize(int Start, int End) { + return Peer->ConSetCursorSize(Start, End); +} + +int GView::QuerySbVPos() { + return Peer->QuerySbVPos(); +} + +int GView::SetSbVPos(int Start, int Amount, int Total) { + return Peer->SetSbVPos(Start, Amount, Total); +} + +int GView::SetSbHPos(int Start, int Amount, int Total) { + return Peer->SetSbHPos(Start, Amount, Total); +} + +int GView::ExpandHeight(int DeltaY) { + return Peer->ExpandHeight(DeltaY); +} + +void GView::Update() { +} + +void GView::Repaint() { +} + +void GView::HandleEvent(TEvent &Event) { +} + +void GView::Resize(int width, int height) { + Repaint(); +} + +void GView::EndExec(int NewResult) { + Result = NewResult; +} + +int GView::Execute() { + int SaveRc = Result; + int NewResult; + int didFocus = 0; + + if (FocusCapture == 0) { + if (CaptureFocus(1) == 0) return -1; + didFocus = 1; + } else + if (FocusCapture != this) + return -1; + Result = -2; + while (Result == -2 && frames != 0) + gui->ProcessEvent(); + NewResult = Result; + Result = SaveRc; + if (didFocus) + CaptureFocus(0); + return NewResult; +} + +int GView::IsActive() { + return (Parent->Active == this && Parent == frames); +} + +void GView::Activate(int gotfocus) { + if (gotfocus) { + Peer->wState |= sfFocus; + Peer->UpdateCursor(); + } else { + Peer->wState &= ~sfFocus; + } + Repaint(); +} + +int GView::CaptureMouse(int grab) { + if (MouseCapture == 0) { + if (grab) { + MouseCapture = this; + WinSetCapture(HWND_DESKTOP, Peer->hwndView); + } else + return 0; + } else { + if (grab || MouseCapture != this) + return 0; + else { + MouseCapture = 0; + WinSetCapture(HWND_DESKTOP, NULLHANDLE); + } + } + return 1; +} + +int GView::CaptureFocus(int grab) { + if (FocusCapture == 0) { + if (grab) { + FocusCapture = this; + WinSetFocus(HWND_DESKTOP, Peer->hwndView); + } else + return 0; + } else { + if (grab || FocusCapture != this) + return 0; + else + FocusCapture = 0; + } + return 1; +} + +/////////////////////////////////////////////////////////////////////////// + +GFramePeer::GFramePeer(GFrame *aFrame, int Width, int Height) { + Frame = aFrame; + + WinSendMsg(hwndCreatorUser, UWM_CREATEFRAME, MPFROMP(this), MPFROMLONG(0)); + + if (Width != -1 && Height != -1) + ConSetSize(Width, Height); +} + +GFramePeer::~GFramePeer() { + WinStoreWindowPos("FTEPM", "Frame1", hwndFrame); + WinSendMsg(hwndFrame, UWM_DESTROY, 0, 0); +} + +int GFramePeer::ConSetSize(int X, int Y) { + //return ::ConSetSize(X, Y); + return 0; +} + +int GFramePeer::ConQuerySize(int *X, int *Y) { +// ::ConQuerySize(&fW, &fH); +// if (X) *X = fW; +// if (Y) *Y = fH; + return 1; +} + +int GFramePeer::ConSetTitle(char *Title, char *STitle) { + char szTitle[256] = {0}; + + JustFileName(Title, szTitle); + if (szTitle[0] == '\0') // if there is no filename, try the directory name. + JustLastDirectory(Title, szTitle); + + if (szTitle[0] != '\0') // if there is something... + strncat(szTitle, " - ", sizeof(szTitle) - 1 - strlen(szTitle)); + strncat(szTitle, Title, sizeof(szTitle) - 1 - strlen(szTitle)); + + WinSetWindowText(hwndFrame, szTitle); + return 1; +} + +int GFramePeer::ConGetTitle(char *Title, int MaxLen, char *STitle, int SMaxLen) { + WinQueryWindowText(hwndFrame, MaxLen, Title); + WinQueryWindowText(hwndFrame, SMaxLen, STitle); + return 1; +} + +void GFramePeer::MapFrame() { + if (frames != frames->Next || WinRestoreWindowPos("FTEPM", "Frame1", hwndFrame) == FALSE) { + WinQueryTaskSizePos(hab, 0, &swp); + + WinSetWindowPos(hwndFrame, HWND_TOP, + swp.x, + swp.y, + swp.cx, + swp.cy, + SWP_MOVE | SWP_SIZE); + } + // WinSendMsg(Peer->hwndFrame, WM_UPDATEFRAME, 0, 0); + SizeFrame(); + ShowFrame(); +} + +void GFramePeer::ShowFrame() { + WinSetWindowPos(hwndFrame, HWND_TOP, 0, 0, 0, 0, + SWP_ZORDER | SWP_SHOW | SWP_ACTIVATE); +} + +void GFramePeer::SizeFrame() { + POINTL ptl; + GView *v = Frame->Top; + SWP swp; + SWP swpMenu; + HWND hwndMenu = WinWindowFromID(hwndFrame, FID_MENU); + SWP swpToolBar; + + if (ShowToolBar) { + HWND hwndToolBar = WinWindowFromID(hwndFrame, FID_MTOOLBAR); + + WinQueryWindowPos(hwndToolBar, &swpToolBar); + WinSendMsg(hwndToolBar, + WM_ADJUSTWINDOWPOS, + MPFROMP(&swpToolBar), + MPARAM(0)); + } else { + swpToolBar.cy = 0; + } + + WinQueryWindowPos(hwndMenu, &swpMenu); + WinSendMsg(hwndMenu, + WM_ADJUSTWINDOWPOS, + MPFROMP(&swpMenu), + MPARAM(0)); + + //WinEnableWindowUpdate(hwndFrame, FALSE); + DosRequestMutexSem(hmtxPMData, SEM_INDEFINITE_WAIT); + ptl.x = v->Peer->wW * v->Peer->pmData->cxChar + cxScrollBar + 2 * cxBorder; + ptl.y = 2 * cyBorder + cyTitleBar + swpMenu.cy + swpToolBar.cy; + + while (v) { + v = v->Prev; + ptl.y += v->Peer->wH * v->Peer->pmData->cyChar + cyScrollBar; + if (v == Frame->Top) break; + } + + reportSize = 0; + DosReleaseMutexSem(hmtxPMData); + WinQueryWindowPos(hwndFrame, &swp); + swp.y = swp.y + swp.cy - ptl.y; + swp.cx = ptl.x; + swp.cy = ptl.y; + WinSendMsg(hwndFrame, + WM_ADJUSTWINDOWPOS, + MPFROMP(&swp), + MPARAM(0)); + WinSetWindowPos(hwndFrame, HWND_TOP, swp.x, swp.y, swp.cx, swp.cy, SWP_SIZE | SWP_MOVE); + DosRequestMutexSem(hmtxPMData, SEM_INDEFINITE_WAIT); + reportSize = 1; + DosReleaseMutexSem(hmtxPMData); + swp.x = cxBorder; + swp.y = cyBorder; + if (ShowToolBar == 2) { + swp.y += swpToolBar.cy; + } + v = Frame->Top; + while (v) { + v = v->Prev; + swp.cx = v->Peer->wW * v->Peer->pmData->cxChar; + swp.cy = cyScrollBar; + WinSetWindowPos(v->Peer->hwndHscroll, 0, + swp.x, swp.y, swp.cx, swp.cy, SWP_SIZE | SWP_MOVE); + swp.y += cyScrollBar; + swp.cy = v->Peer->wH * v->Peer->pmData->cyChar; + WinSetWindowPos(v->Peer->hwndView, 0, + swp.x, swp.y, swp.cx, swp.cy, SWP_SIZE | SWP_MOVE); + swp.x = v->Peer->wW * v->Peer->pmData->cxChar + cxBorder; + swp.y -= cyScrollBar; + swp.cx = cxScrollBar; + swp.cy = cyScrollBar + v->Peer->wH * v->Peer->pmData->cyChar; + WinSetWindowPos(v->Peer->hwndVscroll, 0, + swp.x, swp.y, swp.cx, swp.cy, SWP_SIZE | SWP_MOVE); + swp.y += cyScrollBar + v->Peer->wH * v->Peer->pmData->cyChar; + swp.x = cxBorder; + if (v == Frame->Top) + break; + } + //WinEnableWindowUpdate(hwndFrame, TRUE); +} + +/////////////////////////////////////////////////////////////////////////// + +GFrame::GFrame(int XSize, int YSize) { + Menu = 0; + if (frames == 0) { + frames = Prev = Next = this; + } else { + Next = frames->Next; + Prev = frames; + frames->Next->Prev = this; + frames->Next = this; + frames = this; + } + Top = Active = 0; + Peer = new GFramePeer(this, XSize, YSize); +} + +GFrame::~GFrame() { + GView *P = Top, *Q; + if (P) do { + Q = P; + P = Q->Next; + Q->Parent = 0; + delete Q; + } while (P != Top); + + Top = Active = 0; + if (Peer) { + delete Peer; + Peer = 0; + } + if (Next == this) { + frames = 0; + //DosBeep(500, 500); +// printf("No more frames\x7\x7\n"); + } else { + Next->Prev = Prev; + Prev->Next = Next; + frames = Next; + frames->Activate(); + } + Next = Prev = 0; +} + +int GFrame::ConSetTitle(char *Title, char *STitle) { + return Peer->ConSetTitle(Title, STitle); +} + +int GFrame::ConGetTitle(char *Title, int MaxLen, char *STitle, int SMaxLen) { + return Peer->ConGetTitle(Title, MaxLen, STitle, SMaxLen); +} + +int GFrame::ConSetSize(int X, int Y) { + return Peer->ConSetSize(X, Y); +} + +int GFrame::ConQuerySize(int *X, int *Y) { + return Peer->ConQuerySize(X, Y); +} + +int GFrame::ConSplitView(GView *view, GView *newview) { + int dmy; + + newview->Parent = this; + view->ConQuerySize(&newview->Peer->wW, &dmy); + newview->Peer->wH = view->Peer->wH - view->Peer->wH / 2 - 1; + view->Peer->wH /= 2; + InsertView(view, newview); + view->ConSetSize(view->Peer->wW, view->Peer->wH); + newview->ConSetSize(newview->Peer->wW, newview->Peer->wH); + Peer->SizeFrame(); + return 0; +} + +int GFrame::ConCloseView(GView *view) { + return 0; +} + +int GFrame::ConResizeView(GView *view, int DeltaY) { + return 0; +} + +int GFrame::AddView(GView *view) { + if (Active != 0) { + return ConSplitView(Active, view); + } else { +// int W, H; + + view->Parent = this; + view->Prev = view->Next = 0; + +// view->Peer->wX = 0; +// view->Peer->wY = 0; +// ConQuerySize(&W, &H); +// view->ConSetSize(W, H); + InsertView(Top, view); + return 0; + } +} + +void GFrame::Update() { + GView *v = Active; + + UpdateMenu(); + while (v) { + v->Update(); + v = v->Next; + if (v == Active) + break; + } +} + +void GFrame::UpdateMenu() { +} + +void GFrame::Repaint() { + GView *v = Active; + + while (v) { + v->Repaint(); + v = v->Next; + if (v == Active) + break; + } +} + +void GFrame::InsertView(GView *Prev, GView *view) { + if (!view) return ; + if (Prev) { + view->Prev = Prev; + view->Next = Prev->Next; + Prev->Next = view; + view->Next->Prev = view; + } else { + view->Prev = view->Next = view; + Top = view; + } + if (Active == 0) { + Active = view; + Active->Activate(1); + } +} + +void GFrame::RemoveView(GView *view) { + if (!view) return ; + + if (Active == view) + Active->Activate(0); + if (view->Next == view) { + Top = Active = 0; + delete this; + } else { + view->Next->Prev = view->Prev; + view->Prev->Next = view->Next; + + if (Top == view) { + Top = view->Next; + Top->ConSetSize(Top->Peer->wW, Top->Peer->wH + view->Peer->wH + 1); + } else { + view->Prev->ConSetSize(view->Prev->Peer->wW, + view->Prev->Peer->wH + view->Peer->wH + 1); + } + + if (Active == view) { + Active = view->Prev; + WinSetFocus(HWND_DESKTOP, Active->Peer->hwndView); + Active->Activate(1); + } + } + Peer->SizeFrame(); +} + +void GFrame::SelectNext(int back) { + GView *c = Active; + + if (c == 0 && Top == 0) + return; + else if (c == 0) + c = Active = Top; + else + if (back) { + Active = Active->Prev; + } else { + Active = Active->Next; + } + if (c != Active) { + c->Activate(0); + Active->Activate(1); + WinSetFocus(HWND_DESKTOP, Active->Peer->hwndView); + } +} + +int GFrame::SelectView(GView *view) { + if (Top == 0) + return 0; + + if (FocusCapture != 0 || MouseCapture != 0) + return 0; + + if (Active) + Active->Activate(0); + Active = view; + if (Active) { + Active->Activate(1); + } + //DosBeep(50, 500); + frames = this; + return 1; +} + +void GFrame::Resize(int width, int height) { + if (!Top) + return; + + if (width < 8 || height < 2) + return; + + if (Top == Top->Next) { + Top->ConSetSize(width, height); + } else { + } +} + +int GFrame::SetMenu(const char *Name) { + //WinAlarm(HWND_DESKTOP, WA_NOTE); + if (Menu && Name && strcmp(Name, Menu) == 0) + return 1; + + free(Menu); + Menu = strdup(Name); + + Peer->menuBar = (HWND)WinSendMsg(hwndCreatorUser, + UWM_CREATEMAINMENU, + MPFROMP(Peer), + MPFROMP(Menu)); + + return 1; +} + +int GFrame::ExecMainMenu(char Sub) { + HWND hwnd; + + hwnd = WinWindowFromID(Peer->hwndFrame, FID_MENU); + if (Sub != 0) { + int count = LONGFROMMR(WinSendMsg(hwnd, MM_QUERYITEMCOUNT, 0, 0)); + SHORT id; + char buf[256]; + int len; + char srch[3] = "~x"; + + srch[1] = (char)toupper(Sub); + + //puts("mainmenu"); + for (SHORT i = 0; i < count; i++) { + id = SHORT1FROMMR(WinSendMsg(hwnd, MM_ITEMIDFROMPOSITION, MPFROMSHORT(i), 0)); + if (id == MIT_ERROR) { + puts("error"); + } else { + //printf("got %d %d\n", i, id); + len = SHORT1FROMMR(WinSendMsg(hwnd, MM_QUERYITEMTEXT, MPFROM2SHORT((id), (sizeof(buf) - 1)), MPFROMP(buf))); + buf[len] = 0; + //puts(buf); + srch[1] = (char)toupper(Sub); + if (strstr(buf, srch) != 0) { + WinSendMsg(hwnd, MM_SELECTITEM, (MPFROM2SHORT(id, 0)), 0); + //printf("select %d %d\n", i, id); + } else { + srch[1] = (char)tolower(Sub); + if (strstr(buf, srch) != 0) { + WinSendMsg(hwnd, MM_SELECTITEM, (MPFROM2SHORT(id, 0)), 0); + //printf("select %d %d\n", i, id); + } + } + } + } + } else { + WinPostMsg(hwnd, MM_STARTMENUMODE, MPFROM2SHORT((Sub ? TRUE : FALSE), FALSE), 0); + } + return 0; +} + +int GFrame::PopupMenu(const char *Name) { + int id = GetMenuId(Name); + + if (id == -1) + return 0; + + + WinSendMsg(hwndCreatorUser, + UWM_CREATEPOPUPMENU, + MPFROMP(Peer), + MPFROMLONG(id)); + return 0; +} + +void GFrame::Show() { + Update(); + Peer->MapFrame(); +} + +void GFrame::Activate() { + frames = this; + Update(); + Peer->ShowFrame(); +} + +// GUI + +GUI::GUI(int &argc, char **argv, int XSize, int YSize) { + fArgc = argc; + fArgv = argv; + hab = WinInitialize(0); + hmq = WinCreateMsgQueue(hab, 0); + assert(0 == DosCreateMutexSem(0, &hmtxPMData, 0, 0)); + + cxBorder = WinQuerySysValue(HWND_DESKTOP, SV_CXSIZEBORDER); + cyBorder = WinQuerySysValue(HWND_DESKTOP, SV_CYSIZEBORDER); + cxScrollBar = WinQuerySysValue(HWND_DESKTOP, SV_CXVSCROLL); + cyScrollBar = WinQuerySysValue(HWND_DESKTOP, SV_CYHSCROLL); + cxScreen = WinQuerySysValue(HWND_DESKTOP, SV_CXSCREEN); + cyScreen = WinQuerySysValue(HWND_DESKTOP, SV_CYSCREEN); + cyTitleBar = WinQuerySysValue(HWND_DESKTOP, SV_CYTITLEBAR); + + // edit window class + WinRegisterClass(hab, szClient, (PFNWP)AVIOWndProc, CS_SIZEREDRAW, 4); + //WinRegisterClass(hab, szSizer, (PFNWP)SizerWndProc, CS_SIZEREDRAW, 4); + + // worker object-window class + WinRegisterClass(hab, szObject, (PFNWP)ObjectWndProc, 0, 4); + + // window that created windows in thr 1 for thr 2 + WinRegisterClass(hab, szCreator, (PFNWP)CreatorWndProc, 0, 0); + + hwndCreatorUser = WinCreateWindow(HWND_DESKTOP, + szCreator, + "FTEPM", + 0, + 0, 0, 0, 0, + HWND_DESKTOP, HWND_TOP, + 0, NULL, NULL); + + assert(0 == DosCreateEventSem(0, &WorkerStarted, 0, 0)); + assert(0 == DosCreateEventSem(0, &StartInterface, 0, 0)); + + _beginthread(WorkThread, FAKE_BEGINTHREAD_NULL PM_STACK_SIZE, 0); + + ULONG ulPostCount; + DosWaitEventSem(WorkerStarted, SEM_INDEFINITE_WAIT); + DosResetEventSem(WorkerStarted, &ulPostCount); + + gui = this; +} + +GUI::~GUI() { + WinDestroyMsgQueue(hmq); + WinTerminate(hab); + gui = 0; +} + +int GUI::ConGrabEvents(TEventMask EventMask) { + return 0; +} + +void GUI::DispatchEvent(GFrame *frame, GView *view, TEvent &Event) { + if (Event.What != evNone) { + if (view) + view->HandleEvent(Event); + } +} + +int GUI::ConSuspend(void) { return 0; } + +int GUI::ConContinue(void) { return 0; } + +int GUI::ConGetEvent(TEventMask EventMask, TEvent *Event, int WaitTime, int Delete, GView **view) { + return ::ConGetEvent(EventMask, Event, WaitTime, Delete, view); +} + +int GUI::ConPutEvent(TEvent Event) { + EventBuf = Event; + return 0; +} + +int GUI::ConFlush(void) { + return 0; +} + +void GUI::ProcessEvent() { + TEvent E; + GView *v; + + if (frames == 0) + return ; + + E.What = evNone; + if (E.What == evNone) { + if (ConGetEvent(evMouseDown | evCommand | evKeyDown, &E, 0, 1, &v) == -1) + ; + } + if (E.What == evNone) { + //DosBeep(500, 100); + frames->Update(); + //DosBeep(1000, 100); + if (ConGetEvent(evMouseDown | evCommand | evKeyDown, &E, -1, 1, &v) == -1) + ; + } + if (E.What != evNone) { + v = E.Msg.View; + DispatchEvent(v->Parent, v, E); + } +} + +int GUI::Run() { + QMSG qmsg; + doLoop = 1; + DosPostEventSem(StartInterface); + while (doLoop != 0 && WinGetMsg(hab, &qmsg, NULLHANDLE, 0, 0)) + WinDispatchMsg(hab, &qmsg); + return 0; +} + +int GUI::ShowEntryScreen() { + return 1; +} + +int GUI::RunProgram(int mode, char *Command) { + char FailBuf[256]; + char *Args; + char *Prog; + int rc; + PID pid; + ULONG sid; + + Prog = getenv("COMSPEC"); + + Args = (char *)malloc(3 + strlen(Command) + 1); + if (Args == NULL) { + return -1; + } + + if (*Command != 0) { + strcpy(Args, "/c "); + strcat(Args, Command); + } else { + Args[0] = 0; + } + + { + STARTDATA sd; + + memset((void *)&sd, 0, sizeof(sd)); + sd.Length = sizeof(sd); + sd.Related = SSF_RELATED_INDEPENDENT; + sd.FgBg = SSF_FGBG_FORE; + sd.TraceOpt = SSF_TRACEOPT_NONE; + sd.PgmTitle = (Command && Command[0] != 0) ? Command : 0; + sd.PgmName = Prog; + sd.PgmInputs = Args; + sd.TermQ = 0; + sd.Environment = 0; + sd.InheritOpt = SSF_INHERTOPT_PARENT; + sd.SessionType = SSF_TYPE_DEFAULT; + sd.IconFile = 0; + sd.PgmHandle = 0; + sd.PgmControl = SSF_CONTROL_VISIBLE;// | ((Command && Command[0] != 0) ? SSF_CONTROL_NOAUTOCLOSE : 0); + sd.ObjectBuffer = FailBuf; + sd.ObjectBuffLen = sizeof(FailBuf); + rc = DosStartSession(&sd, &sid, &pid); + } + + free(Args); + + return rc; +} + +static int CreatePipeChild(ULONG *sid, PID *pid, HPIPE &hfPipe, char *Command) { + static int PCount = 0; + char szPipe[32]; + char FailBuf[256]; + char *Args; + char *Prog; +#if 0 + int arglen = 0; + RESULTCODES rc_code; +#endif + ULONG ulAction; + //ULONG ulNew; + HPIPE hfChildPipe; + HFILE hfNewStdOut = (HFILE)-1, hfNewStdErr = (HFILE)-1; + HFILE hfStdOut = (HFILE)1, hfStdErr = (HFILE)2; + int rc; + + sprintf(szPipe, "\\PIPE\\FTE%d\\CHILD%d", getpid(), PCount); + PCount++; + + rc = DosCreateNPipe(szPipe, &hfPipe, + NP_NOINHERIT | NP_ACCESS_INBOUND, + NP_NOWAIT | NP_TYPE_BYTE | NP_READMODE_BYTE | 1, + 0, 4096, 0); + if (rc != 0) + return -1; + + rc = DosConnectNPipe (hfPipe); + if (rc != 0 && rc != ERROR_PIPE_NOT_CONNECTED) { + DosClose(hfPipe); + return -1; + } + + rc = DosSetNPHState (hfPipe, NP_WAIT | NP_READMODE_BYTE); + if (rc != 0) { + DosClose(hfPipe); + return -1; + } + + rc = DosOpen (szPipe, &hfChildPipe, &ulAction, 0, + FILE_NORMAL, + OPEN_ACTION_OPEN_IF_EXISTS | OPEN_ACTION_FAIL_IF_NEW, + OPEN_ACCESS_WRITEONLY | OPEN_SHARE_DENYREADWRITE, + NULL); + if (rc != 0) { + DosClose (hfPipe); + return -1; + } + + // Duplicate handles + DosDupHandle(hfStdOut, &hfNewStdOut); + DosDupHandle(hfStdErr, &hfNewStdErr); + // Close existing handles for current process + DosClose(hfStdOut); + DosClose(hfStdErr); + // Redirect existing handles to new file + DosDupHandle(hfChildPipe, &hfStdOut); + DosDupHandle(hfChildPipe, &hfStdErr); + // Let started program inherit handles from parent + + Prog = getenv("COMSPEC"); + +#if 0 + Args = (char *)malloc(strlen(Prog) + 1 + + 3 + strlen(Command) + 1 + + 1); + if (Args == NULL) { + DosClose(hfPipe); + return -1; + } + + strcpy(Args, Prog); + arglen = strlen(Args) + 1; + strcpy(Args + arglen, "/c "); + arglen += 3; + strcpy(Args + arglen, Command); + arglen += strlen(Command) + 1; + Args[arglen] = '\0'; +#else + Args = (char *)malloc(3 + strlen(Command) + 1); + if (Args == NULL) { + DosClose(hfPipe); + return -1; + } + + strcpy(Args, "/c "); + strcat(Args, Command); +#endif + + +#if 0 + rc = DosExecPgm(FailBuf, sizeof(FailBuf), + EXEC_ASYNCRESULT, // | EXEC_BACKGROUND, + Args, + 0, + &rc_code, + Prog); +#else + { + STARTDATA sd; + + memset((void *)&sd, 0, sizeof(sd)); + sd.Length = sizeof(sd); + sd.Related = SSF_RELATED_INDEPENDENT; + sd.FgBg = SSF_FGBG_BACK; + sd.TraceOpt = SSF_TRACEOPT_NONE; + sd.PgmTitle = 0; + sd.PgmName = Prog; + sd.PgmInputs = Args; + sd.TermQ = 0; + sd.Environment = 0; + sd.InheritOpt = SSF_INHERTOPT_PARENT; + sd.SessionType = SSF_TYPE_DEFAULT; + sd.IconFile = 0; + sd.PgmHandle = 0; + sd.PgmControl = SSF_CONTROL_INVISIBLE; + sd.ObjectBuffer = FailBuf; + sd.ObjectBuffLen = sizeof(FailBuf); + rc = DosStartSession(&sd, sid, pid); + } +#endif + + free(Args); + + // Get back original handles + DosDupHandle(hfNewStdOut, &hfStdOut); + DosDupHandle(hfNewStdErr, &hfStdErr); + // Close the duplicated handles - no longer needed + DosClose(hfNewStdOut); + DosClose(hfNewStdErr); + + DosClose(hfChildPipe); // pipe one way, close out write end + + if (rc != 0) { + DosClose(hfPipe); + return -1; + } + +#if 0 + pid = rc_code.codeTerminate; // get pid when successful + sid = 0; +#endif + + return 0; +} + +static void _LNK_CONV PipeThread(void *p) { + GPipe *pipe = (GPipe *)p; + HAB hab; + ULONG ulPostCount; + ULONG used; + PID pid; + ULONG sid; + HPIPE hfPipe; +#if 0 + RESULTCODES rc_code; +#endif + int rc; + + hab = WinInitialize(0); + + rc = CreatePipeChild(&sid, &pid, hfPipe, pipe->Command); + + if (rc != 0) { + DosRequestMutexSem(pipe->Access, SEM_INDEFINITE_WAIT); + pipe->reading = 0; + if (pipe->notify) + WinPostMsg(frames->Active->Peer->hwndWorker, UWM_NOTIFY, MPFROMLONG(pipe->notify), MPFROMLONG(pipe->id)); + DosReleaseMutexSem(pipe->Access); + WinTerminate(hab); + return; + } +// fprintf(stderr, "Pipe: Begin: %d\n", pipe->id); + while (1) { + rc = DosRead(hfPipe, pipe->buffer, pipe->buflen, &used); + if (rc < 0) + used = 0; + + DosRequestMutexSem(pipe->Access, SEM_INDEFINITE_WAIT); + pipe->bufused = used; +// fprintf(stderr, "Pipe: fread: %d %d\n", pipe->id, pipe->bufused); + DosResetEventSem(pipe->ResumeRead, &ulPostCount); + if (pipe->bufused == 0) + break; + if (pipe->notify && pipe->stopped) { + WinPostMsg(frames->Active->Peer->hwndWorker, UWM_NOTIFY, MPFROMLONG(pipe->notify), MPFROMLONG(pipe->id)); + pipe->stopped = 0; + } + DosReleaseMutexSem(pipe->Access); + if (pipe->DoTerm) + break; + DosWaitEventSem(pipe->ResumeRead, SEM_INDEFINITE_WAIT); + if (pipe->DoTerm) + break; + } +// fprintf(stderr, "Pipe: pClose: %d\n", pipe->id); + DosClose(hfPipe); + //fprintf(stderr, "Pipe: pClose: %d\n", pipe->id); +#if 0 + rc = DosWaitChild(DCWA_PROCESS, DCWW_WAIT, + &rc_code, + &pid, + pid); + pipe->RetCode = rc_code.codeResult; +#else + //DosStopSession(STOP_SESSION_SPECIFIED, sid); + pipe->RetCode = 0; +#endif + pipe->reading = 0; + if (pipe->notify) + WinPostMsg(frames->Active->Peer->hwndWorker, UWM_NOTIFY, MPFROMLONG(pipe->notify), MPFROMLONG(pipe->id)); + DosReleaseMutexSem(pipe->Access); + WinTerminate(hab); +} + +int GUI::OpenPipe(char *Command, EModel *notify) { + int i; + + for (i = 0; i < MAX_PIPES; i++) { + if (Pipes[i].used == 0) { + Pipes[i].reading = 1; + Pipes[i].stopped = 1; + Pipes[i].id = i; + Pipes[i].bufused = 0; + Pipes[i].bufpos = 0; + Pipes[i].buflen = PIPE_BUFLEN; + Pipes[i].Command = strdup(Command); + Pipes[i].notify = notify; + Pipes[i].DoTerm = 0; + if ((Pipes[i].buffer = (char *)malloc(PIPE_BUFLEN)) == 0) + return -1; + + if (0 != DosCreateMutexSem(0, &Pipes[i].Access, 0, 0)) { + free(Pipes[i].Command); + free(Pipes[i].buffer); + return -1; + } + + if (0 != DosCreateEventSem(0, &Pipes[i].ResumeRead, 0, 0)) { + free(Pipes[i].Command); + free(Pipes[i].buffer); + DosCloseMutexSem(Pipes[i].Access); + return -1; + } + + Pipes[i].tid = _beginthread(PipeThread, + FAKE_BEGINTHREAD_NULL + 16384, &Pipes[i]); + + Pipes[i].used = 1; +// fprintf(stderr, "Pipe Open: %d\n", i); + return i; + } + } + return -1; +} + +int GUI::SetPipeView(int id, EModel *notify) { + if (id < 0 || id > MAX_PIPES) + return -1; + if (Pipes[id].used == 0) + return -1; + DosRequestMutexSem(Pipes[id].Access, SEM_INDEFINITE_WAIT); +// fprintf(stderr, "Pipe View: %d %08X\n", id, notify); + Pipes[id].notify = notify; + DosReleaseMutexSem(Pipes[id].Access); + return 0; +} + +int GUI::ReadPipe(int id, void *buffer, int len) { + int l; + //ULONG ulPostCount; + + if (id < 0 || id > MAX_PIPES) + return -1; + if (Pipes[id].used == 0) + return -1; +// DosQueryEventSem(Pipes[id].ResumeRead, &ulPostCount); +// if (ulPostCount != 0) +// return 0; + DosRequestMutexSem(Pipes[id].Access, SEM_INDEFINITE_WAIT); +// fprintf(stderr, "Pipe Read: Get %d %d\n", id, len); + if (Pipes[id].bufused - Pipes[id].bufpos > 0) { + l = len; + if (l > Pipes[id].bufused - Pipes[id].bufpos) { + l = Pipes[id].bufused - Pipes[id].bufpos; + } + memcpy(buffer, + Pipes[id].buffer + Pipes[id].bufpos, + l); + Pipes[id].bufpos += l; + if (Pipes[id].bufpos == Pipes[id].bufused) { + Pipes[id].bufused = 0; + Pipes[id].bufpos = 0; +// fprintf(stderr, "Pipe Resume Read: %d\n", id); + Pipes[id].stopped = 1; + DosPostEventSem(Pipes[id].ResumeRead); + } + } else if (Pipes[id].reading == 0) + l = -1; + else { + l = 0; + //DosBeep(200, 200); + } +// fprintf(stderr, "Pipe Read: Got %d %d\n", id, l); + DosReleaseMutexSem(Pipes[id].Access); + return l; +} + +int GUI::ClosePipe(int id) { + if (id < 0 || id > MAX_PIPES) + return -1; + if (Pipes[id].used == 0) + return -1; + if (Pipes[id].reading == 1) { + Pipes[id].DoTerm = 1; + DosPostEventSem(Pipes[id].ResumeRead); + DosWaitThread(&Pipes[id].tid, DCWW_WAIT); + } + free(Pipes[id].buffer); + free(Pipes[id].Command); + DosCloseEventSem(Pipes[id].ResumeRead); + DosCloseMutexSem(Pipes[id].Access); +// fprintf(stderr, "Pipe Close: %d\n", id); + Pipes[id].used = 0; + return Pipes[id].RetCode; +} + +int GUI::multiFrame() { + return 1; +} + +void DieError(int rc, const char *msg, ...) { + va_list ap; + char str[1024]; + + va_start(ap, msg); + vsprintf(str, msg, ap); + va_end(ap); + if (hab == 0) + hab = WinInitialize(0); + if (hmq == 0) + hmq = WinCreateMsgQueue(hab, 0); + WinMessageBox(HWND_DESKTOP, HWND_DESKTOP, str, "FTE", 0, MB_OK | MB_ERROR); + WinDestroyMsgQueue(hmq); + WinTerminate(hab); + exit(rc); +} + +char ConGetDrawChar(int index) { + static char tab[] = "\xDA\xBF\xC0\xD9\xC4\xB3\xC2\xC3\xB4\xC1\xC5\x1A\xFA\x04\xC4\x18\x19\xB1\xB0\x1B\x1A"; + + assert(index >= 0 && index < (signed)strlen(tab)); + + return tab[index]; +} diff --git a/src/g_qt.cpp b/src/g_qt.cpp new file mode 100644 index 0000000..03bc9fb --- /dev/null +++ b/src/g_qt.cpp @@ -0,0 +1,2138 @@ +/* g_motif.cpp + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sysdep.h" +#include "console.h" +#include "gui.h" + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +//#include // conflicts with above + +#include +#include + +#include +#include + +#define DEBUGX(x) //printf x + +#define EDIT_BORDER 2 +#define SCROLLBAR_SIZE 16 + +#define MAX_PIPES 4 + +typedef struct { + int used; + int id; + int fd; + int pid; + int stopped; + EModel *notify; + //XtInputId input; +} GPipe; + +static GPipe Pipes[MAX_PIPES] = { + { 0 }, { 0 }, { 0 }, { 0 } +}; + +#define sfFocus 1 + +class QEText: public QWidget { + Q_OBJECT +public: + GViewPeer *view; + + QEText(GViewPeer *peer, QWidget *parent = 0, const char *name = 0); + virtual ~QEText(); + + virtual void handleKeyPressEvent(QKeyEvent *qe); + void ActiveEvent(TEvent &Event); +protected: + void handleMouse(QMouseEvent *qe); + + virtual void resizeEvent(QResizeEvent *qe); + virtual void paintEvent(QPaintEvent *qe); + virtual void mousePressEvent(QMouseEvent *qe); + virtual void mouseMoveEvent(QMouseEvent *qe); + virtual void mouseReleaseEvent(QMouseEvent *qe); + virtual void keyPressEvent(QKeyEvent *qe); + virtual void focusInEvent(QFocusEvent *qe); + virtual void focusOutEvent(QFocusEvent *qe); +}; + +class QEView: public QFrame { + Q_OBJECT +public: + GViewPeer *view; + QEText *text; + QScrollBar *horz; + QScrollBar *vert; + + QEView(GViewPeer *peer, QWidget *parent = 0, const char *name = 0); + virtual ~QEView(); + + void ActiveEvent(TEvent &Event); + void setViewPos(int x, int y, int w, int h); + +//protected: +// virtual void resizeEvent(QResizeEvent *qe); + +protected slots: + void sbHmoveLeft(); + void sbHmoveRight(); + void sbHpageLeft(); + void sbHpageRight(); + void sbHmoveTo(int pos); + + void sbVmoveUp(); + void sbVmoveDown(); + void sbVpageUp(); + void sbVpageDown(); + void sbVmoveTo(int pos); +}; + +class QEFrame : public QFrame { + Q_OBJECT +public: + QMenuBar *menubar; + QEFrame(GFramePeer *peer, QWidget *parent = 0, const char *name = 0); + + QMenuBar *CreateMenuBar(QWidget *parent, int Id); + QPopupMenu *CreatePopup(QWidget *parent, int Id, int do_connect); + +protected: + virtual void resizeEvent(QResizeEvent *qe); + virtual void closeEvent(QCloseEvent *qe); +public slots: + void selectedMain(int id); + void timerDone(); +private: + GFramePeer *frame; +}; + +class GViewPeer { +public: + QEView *qView; + GC GCs[256]; + + GView *View; +// int wX, wY; + int wW, wH, wState, wRefresh; + int cX, cY, cVisible, cStart, cEnd; + int sbVstart, sbVamount, sbVtotal; + int sbHstart, sbHamount, sbHtotal; + int VertPos, HorzPos; + unsigned char *ScreenBuffer; + + GViewPeer(GView *view, int XSize, int YSize); + ~GViewPeer(); + + int AllocBuffer(); + void DrawCursor(/*QPainter *painter, */int Show); + void UpdateWindow(int xx, int yy, int ww, int hh); + + int ConPutBox(int X, int Y, int W, int H, PCell Cell); + int ConGetBox(int X, int Y, int W, int H, PCell Cell); + int ConPutLine(int X, int Y, int W, int H, PCell Cell); + int ConSetBox(int X, int Y, int W, int H, TCell Cell); + int ConScroll(int Way, int X, int Y, int W, int H, TAttr Fill, int Count); + + int ConSetSize(int X, int Y); + int ConQuerySize(int *X, int *Y); + + int ConSetCursorPos(int X, int Y); + int ConQueryCursorPos(int *X, int *Y); + int ConShowCursor(); + int ConHideCursor(); + int ConCursorVisible(); + int ConSetCursorSize(int Start, int End); + + int QuerySbVPos(); + int SetSbVPos(int Start, int Amount, int Total); + int SetSbHPos(int Start, int Amount, int Total); + int ExpandHeight(int DeltaY); + + int UpdateCursor(); + int PMShowCursor(); + int PMHideCursor(); + int PMSetCursorPos(); +}; + +class GFramePeer { +public: + GFrame *Frame; + QEFrame *qFrame; + + GFramePeer(GFrame *aFrame, int Width, int Height); + ~GFramePeer(); + + int ConSetTitle(char *Title, char *STitle); + int ConGetTitle(char *Title, int MaxLen, char *STitle, int SMaxLen); + + int ConSetSize(int X, int Y); + int ConQuerySize(int *X, int *Y); + void MapFrame(); + void ShowFrame(); +}; + +int ShowVScroll = 1; +int ShowHScroll = 0; +int ShowMenuBar = 1; +int ShowToolBar = 0; + +GFrame *frames = 0; +GUI *gui = 0; + +static GView *MouseCapture = 0; +static GView *FocusCapture = 0; + +static int cxChar = 1; +static int cyChar = 1; +static int fmAscent; +static int FinalExit = 0; + +TEvent EventBuf = { evNone }; + +typedef struct _qEvent { + TEvent event; + struct _qEvent *next; +} qEvent; + +TEvent NextEvent = { evNone }; +static QColor colors[16] = { + black, + darkBlue, + darkGreen, + darkCyan, + darkRed, + darkMagenta, + darkYellow, + gray, + + darkGray, + blue, + green, + cyan, + red, + magenta, + yellow, + white, +}; + +static XFontStruct *fontStruct; +static Display *display; + +static QPoint LastMousePos; + +static int LastMouseX = -1, LastMouseY = -1; + +static qEvent *event_head = 0; +static qEvent *event_tail = 0; + +static int qPutEvent(TEvent &Event) { + qEvent *q = new qEvent; + + q->event = Event; + q->next = 0; + + if (event_tail) { + event_tail->next = q; + event_tail = q; + } else { + event_head = event_tail = q; + } + FinalExit = 0; + qApp->exit_loop(); + return 0; +} + +static int qHasEvent() { + return event_head ? 1 : 0; +} + +static void qGetEvent(TEvent &Event) { + qEvent *q = event_head; + + Event = q->event; + event_head = q->next; + if (!event_head) + event_tail = 0; + delete q; +} + +QEView::QEView(GViewPeer *peer, QWidget *parent, const char *name): QFrame(parent, name) +{ + view = peer; + + text = new QEText(peer, this); + CHECK_PTR(text); + horz = new QScrollBar(QScrollBar::Horizontal, parent, 0); + CHECK_PTR(horz); + vert = new QScrollBar(QScrollBar::Vertical, parent, 0); + CHECK_PTR(vert); + horz->show(); + vert->show(); + + setFrameStyle(Panel|Sunken); + setLineWidth(EDIT_BORDER); + + connect(vert, SIGNAL(valueChanged(int)), SLOT(sbVmoveTo(int))); + connect(vert, SIGNAL(sliderMoved(int)), SLOT(sbVmoveTo(int))); + connect(vert, SIGNAL(prevLine()), SLOT(sbVmoveUp())); + connect(vert, SIGNAL(nextLine()), SLOT(sbVmoveDown())); + connect(vert, SIGNAL(prevPage()), SLOT(sbVpageUp())); + connect(vert, SIGNAL(nextPage()), SLOT(sbVpageDown())); + + connect(horz, SIGNAL(valueChanged(int)), SLOT(sbHmoveTo(int))); + connect(horz, SIGNAL(sliderMoved(int)), SLOT(sbHmoveTo(int))); + connect(horz, SIGNAL(prevLine()), SLOT(sbHmoveLeft())); + connect(horz, SIGNAL(nextLine()), SLOT(sbHmoveRight())); + connect(horz, SIGNAL(prevPage()), SLOT(sbHpageLeft())); + connect(horz, SIGNAL(nextPage()), SLOT(sbHpageRight())); +} + +QEView::~QEView() { + delete horz; + delete vert; +} + +void QEView::setViewPos(int x, int y, int w, int h) { + setGeometry(x, y, w - SCROLLBAR_SIZE, h - SCROLLBAR_SIZE); + text->setGeometry(contentsRect()); + vert->setGeometry(x + w - SCROLLBAR_SIZE, y, SCROLLBAR_SIZE, h - SCROLLBAR_SIZE); + horz->setGeometry(x, y + h - SCROLLBAR_SIZE, w - SCROLLBAR_SIZE, SCROLLBAR_SIZE); +} + +void QEView::ActiveEvent(TEvent &Event) { + if (!view->View->IsActive()) + view->View->Parent->SelectView(view->View); + qPutEvent(Event); +} + +void QEView::sbHmoveLeft() { + NextEvent.What = evCommand; + NextEvent.Msg.View = view->View; + NextEvent.Msg.Command = cmHScrollLeft; + ActiveEvent(NextEvent); +} + +void QEView::sbHmoveRight() { + NextEvent.What = evCommand; + NextEvent.Msg.View = view->View; + NextEvent.Msg.Command = cmHScrollRight; + ActiveEvent(NextEvent); +} + +void QEView::sbHpageLeft() { + NextEvent.What = evCommand; + NextEvent.Msg.View = view->View; + NextEvent.Msg.Command = cmHScrollPgLt; + ActiveEvent(NextEvent); +} + +void QEView::sbHpageRight() { + NextEvent.What = evCommand; + NextEvent.Msg.View = view->View; + NextEvent.Msg.Command = cmHScrollPgRt; + ActiveEvent(NextEvent); +} + +void QEView::sbHmoveTo(int pos) { + NextEvent.What = evCommand; + NextEvent.Msg.View = view->View; + NextEvent.Msg.Command = cmHScrollMove; + NextEvent.Msg.Param1 = pos; + ActiveEvent(NextEvent); +} + +void QEView::sbVmoveUp() { + NextEvent.What = evCommand; + NextEvent.Msg.View = view->View; + NextEvent.Msg.Command = cmVScrollUp; + ActiveEvent(NextEvent); +} + +void QEView::sbVmoveDown() { + NextEvent.What = evCommand; + NextEvent.Msg.View = view->View; + NextEvent.Msg.Command = cmVScrollDown; + ActiveEvent(NextEvent); +} + +void QEView::sbVpageUp() { + NextEvent.What = evCommand; + NextEvent.Msg.View = view->View; + NextEvent.Msg.Command = cmVScrollPgUp; + ActiveEvent(NextEvent); +} + +void QEView::sbVpageDown() { + NextEvent.What = evCommand; + NextEvent.Msg.View = view->View; + NextEvent.Msg.Command = cmVScrollPgDn; + ActiveEvent(NextEvent); +} + +void QEView::sbVmoveTo(int pos) { + NextEvent.What = evCommand; + NextEvent.Msg.View = view->View; + NextEvent.Msg.Command = cmVScrollMove; + NextEvent.Msg.Param1 = pos; + ActiveEvent(NextEvent); +} + + +QEText::QEText(GViewPeer *peer, QWidget *parent, const char *name): QWidget(parent, name) { + view = peer; + + setAcceptFocus(TRUE); + setMinimumSize(100, 80); +} + +QEText::~QEText() { +} + +void QEText::resizeEvent(QResizeEvent *qe) { + int X, Y; + + DEBUGX(("A: %X\n", qe)); + QWidget::resizeEvent(qe); + DEBUGX(("B\n")); + + X = qe->size().width(); + Y = qe->size().height(); //qe->size().height() - frameWidth() * 2; + DEBUGX(("Resize %d, %d\n", X, Y)); + X /= cxChar; + Y /= cyChar; + DEBUGX(("!! Resize %d, %d\n", X, Y)); + if (X > 0 && Y > 0) { + view->ConSetSize(X, Y); + NextEvent.What = evCommand; + NextEvent.Msg.View = view->View; + NextEvent.Msg.Command = cmResize; + qPutEvent(NextEvent); + } +} + +void QEText::paintEvent(QPaintEvent *qe) { + view->UpdateWindow(qe->rect().x(), + qe->rect().y(), + qe->rect().width(), + qe->rect().height()); +} + +void QEText::handleMouse(QMouseEvent *qe) { + int event = qe->button(); + int state = qe->state(); + int X = (qe->pos().x()/* - frameWidth()*/) / cxChar; + int Y = (qe->pos().y()/* - frameWidth()*/) / cyChar; + + NextEvent.Mouse.View = view->View; + + LastMousePos = mapToGlobal(qe->pos()); + + switch (qe->type()) { + case Event_MouseButtonPress: + case Event_MouseButtonDblClick: + if (!view->View->IsActive()) + view->View->Parent->SelectView(view->View); + NextEvent.What = evMouseDown; + break; + case Event_MouseButtonRelease: + NextEvent.What = evMouseUp; + break; + case Event_MouseMove: + NextEvent.What = evMouseMove; + break; + default: + return ; + } + NextEvent.Mouse.Buttons = 0; + + if (NextEvent.What == evMouseMove) { + if (state & LeftButton) + NextEvent.Mouse.Buttons |= 1; + if (state & RightButton) + NextEvent.Mouse.Buttons |= 2; + if (state & MidButton) + NextEvent.Mouse.Buttons |= 4; + } else { + if (event & LeftButton) + NextEvent.Mouse.Buttons |= 1; + if (event & RightButton) + NextEvent.Mouse.Buttons |= 2; + if (event & MidButton) + NextEvent.Mouse.Buttons |= 4; + } + NextEvent.Mouse.KeyMask = 0; + if (state & ShiftButton) + NextEvent.Mouse.KeyMask |= kfShift; + if (state & ControlButton) + NextEvent.Mouse.KeyMask |= kfCtrl; + if (state & AltButton) + NextEvent.Mouse.KeyMask |= kfAlt; + + NextEvent.Mouse.Count = 1; + if (qe->type() == Event_MouseButtonDblClick) + NextEvent.Mouse.Count = 2; + NextEvent.Mouse.X = X; + NextEvent.Mouse.Y = Y; + qPutEvent(NextEvent); +} + + +void QEText::mousePressEvent(QMouseEvent *qe) { + handleMouse(qe); +} + +void QEText::mouseMoveEvent(QMouseEvent *qe) { + handleMouse(qe); +} + +void QEText::mouseReleaseEvent(QMouseEvent *qe) { + handleMouse(qe); +} + +static struct { + unsigned int q_code; + TKeyCode keyCode; +} key_table[] = { +{ Key_Escape, kbEsc }, +{ Key_Tab, kbTab }, +{ Key_Backtab, kbTab | kfShift }, +{ Key_Backspace, kbBackSp }, +{ Key_Return, kbEnter }, +{ Key_Enter, kbEnter }, +{ Key_Insert, kbIns }, +{ Key_Delete, kbDel }, +{ Key_Pause, kbPause }, +{ Key_Print, kbPrtScr }, +{ Key_SysReq, kbSysReq }, +{ Key_Home, kbHome }, +{ Key_End, kbEnd }, +{ Key_Left, kbLeft }, +{ Key_Up, kbUp }, +{ Key_Right, kbRight }, +{ Key_Down, kbDown }, +{ Key_Prior, kbPgUp }, +{ Key_Next, kbPgDn }, +{ Key_Shift, kbShift | kfModifier }, +{ Key_Control, kbCtrl | kfModifier }, +{ Key_Meta, kbAlt | kfModifier }, +{ Key_Alt, kbAlt | kfModifier }, +{ Key_CapsLock, kbCapsLock | kfModifier }, +{ Key_NumLock, kbNumLock | kfModifier }, +{ Key_ScrollLock, kbScrollLock | kfModifier }, +{ Key_F1, kbF1 }, +{ Key_F2, kbF2 }, +{ Key_F3, kbF3 }, +{ Key_F4, kbF4 }, +{ Key_F5, kbF5 }, +{ Key_F6, kbF6 }, +{ Key_F7, kbF7 }, +{ Key_F8, kbF8 }, +{ Key_F9, kbF9 }, +{ Key_F10, kbF10 }, +{ Key_F11, kbF11 }, +{ Key_F12, kbF12 }, +}; + +void QEText::ActiveEvent(TEvent &Event) { + if (!view->View->IsActive()) + view->View->Parent->SelectView(view->View); + qPutEvent(Event); +} + +void QEText::handleKeyPressEvent(QKeyEvent *qe) { + TKeyCode keyCode; + TKeyCode keyFlags; + int state = qe->state(); + int ascii = qe->ascii(); + int key = qe->key(); + + DEBUGX(("key: %d, ascii: %d(%c) state:%X\n", + qe->key(), + qe->ascii(), + qe->ascii(), + qe->state())); + + keyFlags = 0; + if (state & ShiftButton) + keyFlags |= kfShift; + if (state & ControlButton) + keyFlags |= kfCtrl; + if (state & AltButton) + keyFlags |= kfAlt; + + keyCode = 0; + for (int i = 0; i < (sizeof(key_table)/sizeof(key_table[0])); i++) { + if (key == key_table[i].q_code) { + keyCode = key_table[i].keyCode; + break; + } + } + if (keyCode == 0 && ascii != 0) { + if (keyFlags & (kfCtrl | kfAlt)) { + keyCode = toupper(ascii); + } else { + keyCode = ascii; + } + } + if (keyCode == 0) { + QWidget::keyPressEvent(qe); + return; + } + + DEBUGX(("key: %d, flags:%d\n", keyCode, keyFlags)); + + NextEvent.What = evKeyDown; + NextEvent.Key.View = view->View; + NextEvent.Key.Code = keyCode | keyFlags; + qPutEvent(NextEvent); +} + +void QEText::keyPressEvent(QKeyEvent *qe) { + handleKeyPressEvent(qe); +} + +//void QEFrame::keyPressEvent(QKeyEvent *qe) { +// frame->Frame->Active->Peer->qView->handleKeyPressEvent(qe); +//} + +void QEText::focusInEvent(QFocusEvent *qe) { + //repaint(FALSE); + DEBUGX(("got focus\n")); +} + +void QEText::focusOutEvent(QFocusEvent *qe) { + //repaint(FALSE); + DEBUGX(("lost focus\n")); +} + +QEFrame::QEFrame(GFramePeer *peer, QWidget *parent, const char *name): QFrame(parent, name) +{ + frame = peer; + menubar = 0; + //setAcceptFocus(TRUE); +} + +void QEFrame::resizeEvent(QResizeEvent *qe) { + int y = 0; + int x = 0; + int h = qe->size().height(); + int w = qe->size().width(); + int count, cur; + int cy, ch; + + GView *p; + + if (menubar) { + h -= menubar->height(); + y += menubar->height(); + } + + p = frame->Frame->Top; + count = 0; + if (p) do { + count++; + p = p->Next; + } while (p != frame->Frame->Top); + + DEBUGX(("count: %d size: %d %d\n", count, w, h)); + + p = frame->Frame->Top; + cur = 0; + if (p) do { + ch = h / count; + if (p->Next == frame->Frame->Top) + ch = h - (h / count) * (count - 1); + cy = y + h * cur / count; + cur++; + DEBUGX(("setting: %d %d %d %d\n", x, cy, w, ch)); + p->Peer->qView->setViewPos(x, cy, w, ch); + p = p->Next; + } while (p != frame->Frame->Top); + +// frame->Frame->Top->Peer->qView->SetViewGeom(x, y, w, h); +} + +void QEFrame::closeEvent(QCloseEvent *qe) { + DEBUGX(("Close Selected: %d\n", id)); + NextEvent.What = evCommand; + NextEvent.Msg.View = frame->Frame->Active; + NextEvent.Msg.Command = cmClose; + qPutEvent(NextEvent); +} + +void QEFrame::selectedMain(int id) { + DEBUGX(("Menu Selected: %d\n", id)); + NextEvent.What = evCommand; + NextEvent.Msg.View = frame->Frame->Active; + NextEvent.Msg.Command = id; + qPutEvent(NextEvent); +} + +#include "g_qt.moc" + +#if 0 + +void ProcessXEvents(XEvent *event, TEvent *Event, GViewPeer *Peer) { + XAnyEvent *anyEvent = (XAnyEvent *) event; + XExposeEvent *exposeEvent = (XExposeEvent *) event; + XButtonEvent *buttonEvent = (XButtonEvent *) event; + XKeyEvent *keyEvent = (XKeyEvent *) event; + XKeyEvent keyEvent1; + XConfigureEvent *configureEvent = (XConfigureEvent *) event; + XGraphicsExposeEvent *gexposeEvent = (XGraphicsExposeEvent *) event; + XMotionEvent *motionEvent = (XMotionEvent *) event; + KeySym key, key1; + int state; + char keyName[32]; + char keyName1[32]; + static int hasConfig = 0; + + Event->What = evNone; + Event->Msg.View = Peer->View; + + switch (event->type) { + case ButtonRelease: + case ButtonPress: + LastRelease = *buttonEvent; + ConvertClickToEvent(event->type, buttonEvent->x, buttonEvent->y, buttonEvent->button, buttonEvent->state, Event, motionEvent->time); + break; + case KeyPress: + case KeyRelease: + state = keyEvent->state; + + keyEvent1 = *keyEvent; + keyEvent1.state &= ~(ShiftMask | ControlMask | Mod1Mask | Mod2Mask | Mod3Mask | Mod4Mask); + + XLookupString(keyEvent, keyName, sizeof(keyName), &key, 0); + XLookupString(&keyEvent1, keyName1, sizeof(keyName1), &key1, 0); + //key1 = XLookupKeysym(keyEvent, 0); + ConvertKeyToEvent(key, key1, keyName, event->type, state, Event); + break; + case MotionNotify: + ConvertClickToEvent(event->type, motionEvent->x, motionEvent->y, 0, motionEvent->state, Event, motionEvent->time); + break; + } +} + +static void CloseWindow(Widget w, GFramePeer *frame, XEvent *event, Boolean *cont) { + if (event->type != ClientMessage || + ((XClientMessageEvent *)event)->data.l[0] != WM_DELETE_WINDOW) + { + return ; + } + NextEvent.What = evCommand; + NextEvent.Msg.Command = cmClose; + *cont = False; +} + +#endif +/////////////////////////////////////////////////////////////////////////// + +GViewPeer::GViewPeer(GView *view, int XSize, int YSize) { + + View = view; + + // wX = 0; + // wY = 0; + wW = XSize; + wH = YSize; + sbVtotal = 0; + sbVstart = 0; + sbVamount = 0; + sbHtotal = 0; + sbHstart = 0; + sbHamount = 0; + wState = 0; + cVisible = 1; + cStart = 0; // % + cEnd = 100; + wRefresh = 0; + ScreenBuffer = 0; + cX = -1; + cY = -1; + VertPos = HorzPos = -1; + + for (int jj = 0; jj < 256; jj++) + GCs[jj] = 0; + + qView = new QEView(this, frames->Peer->qFrame); + qView->show(); +} + +GViewPeer::~GViewPeer() { + delete qView; +} + +int GViewPeer::AllocBuffer() { + int i; + unsigned char *p; + + ScreenBuffer = (unsigned char *)malloc(2 * wW * wH); + if (ScreenBuffer == NULL) return -1; + for (i = 0, p = ScreenBuffer; i < wW * wH; i++) { + *p++ = 32; + *p++ = 0x07; + } + return 0; +} + +#define InRange(x,a,y) (((x) <= (a)) && ((a) < (y))) +#define CursorXYPos(x,y) (ScreenBuffer + ((x) + ((y) * wW)) * 2) + +void GViewPeer::DrawCursor(/*QPainter *painter, */int Show) { + if (!(View && View->Parent)) + return ; + + if (qView->text->winId() == 0) + return ; + + if (!(wState & sfFocus)) + Show = 0; + + if (cX >= wW || cY >= wW || + cX + 1 > wW || cY + 1 > wH) + { + DEBUGX(("bounds %d %d\n", wW, wH)); + return; + } + + DEBUGX(("DrawCursor %d %d\n", cX, cY)); + // if (!XtIsManaged(TextWin)) return ; + + if (cVisible && cX >= 0 && cY >= 0) { + char *p = CursorXYPos(cX, cY); + unsigned char attr; + + attr = p[1]; + //if (Show) attr = ((((attr << 4) & 0xF0)) | (attr >> 4)) ^ 0x77; + if (Show) attr = (attr ^ 0x77); + + if (GCs[attr] == 0) { + XGCValues gcv; + + gcv.foreground = colors[attr & 0xF].pixel(); + gcv.background = colors[(attr >> 4) & 0xF].pixel(); + gcv.font = fontStruct->fid; + GCs[attr] = XCreateGC(display, qView->text->winId(), + GCForeground | GCBackground | GCFont, + &gcv); + } + + XDrawImageString(display, qView->text->winId(), GCs[attr & 0xFF], + /*qView->frameWidth() +*/ cX * cxChar, + /*qView->frameWidth() +*/ fontStruct->max_bounds.ascent + cY * cyChar, + (char *)p, 1); + + /*inter->setPen(colors[attr & 0xF]); + painter->setBackgroundColor(colors[(attr >> 4) & 0xF]); + + painter->drawText(qView->frameWidth() + cX * cxChar, + qView->frameWidth() + cY * cyChar + fmAscent, + p, 1);*/ + } +} + +int GViewPeer::ConPutBox(int X, int Y, int W, int H, PCell Cell) { + int i; + unsigned char temp[256], attr; + unsigned char *p, *ps, *c, *ops; + int len, x, l, ox, olen, skip; + //int local_painter = 0; + + + if (!(View && View->Parent)) + return 1; + + if (qView->text->winId() == 0) + return 1; + + //if (Visibility == VisibilityFullyObscured) + // return - 1; + + if (X >= wW || Y >= wH || + X + W > wW || Y + H > wH) + { + DEBUGX(("bounds %d %d\n",wW, wH)); + return -1; + } + + /*if (qView->Painter == 0) { + DEBUGX(("{{{ New painter\n")); + qView->Painter = new QPainter(); + qView->Painter->begin(qView); + local_painter = 1; + } + qView->Painter->setBackgroundMode(OpaqueMode); + qView->Painter->setFont(Font);*/ + + DEBUGX(("PutBox %d | %d %d %d %d | %d %d\n", wRefresh, X, Y, W, H, wW, wH)); + for (i = 0; i < H; i++) { + len = W; + p = CursorXYPos(X, Y + i); + ps = (unsigned char *) Cell; + x = X; + while (len > 0) { + if (!wRefresh) { + c = CursorXYPos(x, Y + i); + skip = 0; + ops = ps; + ox = x; + olen = len; + while ((len > 0) && (*(unsigned short *) c == *(unsigned short *)ps)) x++, len--, ps+=2, c+=2, skip++; + if (len <= 0) break; + if (skip <= 4) { + ps = ops; + x = ox; + len = olen; + } + } + p = ps; + l = 1; + temp[0] = *ps++; attr = *ps++; + while ((l < len) && ((unsigned char) (ps[1]) == attr)) { + temp[l++] = *ps++; + ps++; + } + + /*qView->Painter->setPen(colors[attr & 0xF]); + qView->Painter->setBackgroundColor(colors[(attr >> 4) & 0xF]); + + qView->Painter->drawText(qView->frameWidth() + x * cxChar, + qView->frameWidth() + (Y + i) * cyChar + fmAscent, + (char *)temp, l);*/ + + if (GCs[attr] == 0) { + XGCValues gcv; + + gcv.foreground = colors[attr & 0xF].pixel(); + gcv.background = colors[(attr >> 4) & 0xF].pixel(); + gcv.font = fontStruct->fid; + GCs[attr] = XCreateGC(display, qView->text->winId(), + GCForeground | GCBackground | GCFont, + &gcv); + } + + XDrawImageString(display, qView->text->winId(), GCs[attr & 0xFF], + /*qView->frameWidth() +*/ x * cxChar, + /*qView->frameWidth() +*/ fontStruct->max_bounds.ascent + (Y + i) * cyChar, + (char *)temp, l); + + x += l; + len -= l; + } + p = CursorXYPos(X, Y + i); + memcpy(p, Cell, W * 2); + if (i + Y == cY) + DrawCursor(1); + Cell += W; + } + /*if (local_painter) { + DEBUGX(("}}} Destroying painter\n")); + qView->Painter->end(); + delete qView->Painter; + qView->Painter = 0; + }*/ + DEBUGX(("done putbox\n")); + return 0; +} + +void GViewPeer::UpdateWindow(int xx, int yy, int ww, int hh) { + PCell p; + int i; + ww /= cxChar; ww += 2; + hh /= cyChar; hh += 2; + xx /= cxChar; + yy /= cyChar; + if (xx + ww > wW) ww = wW - xx; + if (yy + hh > wH) hh = wH - yy; + wRefresh = 1; + p = (PCell) CursorXYPos(xx, yy); + for (i = 0; i < hh; i++) { + ConPutBox(xx, yy + i, ww, 1, p); + p += wW; + } + //XFlush(display); + wRefresh = 0; +} + +int GViewPeer::ConGetBox(int X, int Y, int W, int H, PCell Cell) { + int i; + + for (i = 0; i < H; i++) { + memcpy(Cell, CursorXYPos(X, Y + i), 2 * W); + Cell += W; + } + return 0; +} + +int GViewPeer::ConPutLine(int X, int Y, int W, int H, PCell Cell) { + int i; + + for (i = 0; i < H; i++) { + if (ConPutBox(X, Y + i, W, 1, Cell) != 0) return -1; + } + return 0; +} + +int GViewPeer::ConSetBox(int X, int Y, int W, int H, TCell Cell) { + TDrawBuffer B; + int i; + + for (i = 0; i < W; i++) B[i] = Cell; + ConPutLine(X, Y, W, H, B); + return 0; +} + +int GViewPeer::ConScroll(int Way, int X, int Y, int W, int H, TAttr Fill, int Count) { + TCell Cell; + int l; + int fw = 0; //qView->frameWidth(); + + if (qView->text->winId() == 0) + return 1; + + if (GCs[Fill] == 0) { + XGCValues gcv; + + gcv.foreground = colors[Fill & 0xF].pixel(); + gcv.background = colors[(Fill >> 4) & 0xF].pixel(); + gcv.font = fontStruct->fid; + GCs[Fill] = XCreateGC(display, qView->text->winId(), + GCForeground | GCBackground | GCFont, + &gcv); + } + + MoveCh(&Cell, ' ', Fill, 1); + DrawCursor(0); + if (Way == csUp) { + XCopyArea(display, qView->text->winId(), qView->text->winId(), GCs[Fill], + fw + X * cxChar, + fw + (Y + Count) * cyChar, + W * cxChar, + (H - Count) * cyChar, + fw + X * cxChar, + fw + Y * cyChar + ); + for (l = 0; l < H - Count; l++) { + memcpy(CursorXYPos(X, Y + l), CursorXYPos(X, Y + l + Count), 2 * W); + } + if (ConSetBox(X, Y + H - Count, W, Count, Cell) == -1) return -1; + } else if (Way == csDown) { + XCopyArea(display, qView->text->winId(), qView->text->winId(), GCs[Fill], + fw + X * cxChar, + fw + Y * cyChar, + W * cxChar, + (H - Count) * cyChar, + fw + X * cxChar, + fw + (Y + Count)* cyChar + ); + for (l = H - 1; l >= Count; l--) { + memcpy(CursorXYPos(X, Y + l), CursorXYPos(X, Y + l - Count), 2 * W); + } + if (ConSetBox(X, Y, W, Count, Cell) == -1) return -1; + } + DrawCursor(1); + return 0; + + /*TCell Cell; + int l; + + MoveCh(&Cell, ' ', Fill, 1); + QPainter painter; + painter.begin(qView); + painter.setBackgroundMode(OpaqueMode); + painter.setFont(Font); + DrawCursor(&painter, 0); + if (Way == csUp) { + bitBlt(qView, + qView->frameWidth() + X * cxChar, + qView->frameWidth() + Y * cyChar, + qView, + qView->frameWidth() + X * cxChar, + qView->frameWidth() + (Y + Count) * cyChar, + W * cxChar, (H - Count) * cyChar, + CopyROP, TRUE); + for (l = 0; l < H - Count; l++) { + memcpy(CursorXYPos(X, Y + l), CursorXYPos(X, Y + l + Count), 2 * W); + } + } else if (Way == csDown) { + bitBlt(qView, + qView->frameWidth() + X * cxChar, + qView->frameWidth() + (Y + Count) * cyChar, + qView, + qView->frameWidth() + X * cxChar, + qView->frameWidth() + Y * cyChar, + W * cxChar, (H - Count) * cyChar, + CopyROP, TRUE); + for (l = H - 1; l >= Count; l--) { + memcpy(CursorXYPos(X, Y + l), CursorXYPos(X, Y + l - Count), 2 * W); + } + } + DrawCursor(&painter, 1); + painter.end(); + if (Way == csUp) { + ConSetBox(X, Y, W, Count, Cell); + } else if (Way == csDown) { + ConSetBox(X, Y + H - Count, W, Count, Cell); + } + return 0;*/ +} + +int GViewPeer::ConSetSize(int X, int Y) { + unsigned char *NewBuffer; + unsigned char *p; + int i; + unsigned int MX, MY; + + p = NewBuffer = (unsigned char *) malloc(X * Y * 2); + if (NewBuffer == NULL) return -1; + for (i = 0; i < X * Y; i++) { + *p++ = ' '; + *p++ = 0x07; + } + if (ScreenBuffer) { + MX = wW; if (X < MX) MX = X; + MY = wH; if (Y < MY) MY = Y; + if (X < MX) MX = X; + p = NewBuffer; + for (i = 0; i < MY; i++) { + memcpy(p, CursorXYPos(0, i), MX * 2); + p += X * 2; + } + free(ScreenBuffer); + } + ScreenBuffer = NewBuffer; + wW = X; + wH = Y; + wRefresh = 1; + View->Resize(wW, wH); + ConPutBox(0, 0, wW, wH, (PCell) ScreenBuffer); + wRefresh = 0; +// if (Refresh == 0) +// qView->setSize(0, +// XResizeWindow(display, win, ScreenCols * cxChar, ScreenRows * cyChar); + qView->show(); + return 1; +} + +int GViewPeer::ConQuerySize(int *X, int *Y) { + if (X) *X = wW; + if (Y) *Y = wH; + return 1; +} + +int GViewPeer::ConSetCursorPos(int X, int Y) { + if (X < 0) X = 0; + if (X >= wW) X = wW - 1; + if (Y < 0) Y = 0; + if (Y >= wH) Y = wH - 1; + + /*QPainter painter; + painter.begin(qView); + painter.setBackgroundMode(OpaqueMode); + painter.setFont(Font);*/ + DrawCursor(0); + cX = X; + cY = Y; + DrawCursor(1); + //painter.end(); + return 1; +} + +int GViewPeer::ConQueryCursorPos(int *X, int *Y) { + if (X) *X = cX; + if (Y) *Y = cY; + return 1; +} + +int GViewPeer::ConShowCursor() { + cVisible = 1; +// DrawCursor(1); + return 1; +} + +int GViewPeer::ConHideCursor() { + cVisible = 0; + // DrawCursor(0); + return 1; +} + +int GViewPeer::ConCursorVisible() { + return cVisible; +} + +int GViewPeer::ConSetCursorSize(int Start, int End) { + cStart = Start; + cEnd = End; + if (wState & sfFocus) + return 1; //PMSetCursorSize(Start, End); + else + return 1; +} + +int GViewPeer::ExpandHeight(int DeltaY) { + return 0; +} + +int GViewPeer::QuerySbVPos() { + return sbVstart; +} + +int GViewPeer::SetSbVPos(int Start, int Amount, int Total) { + if (sbVstart != Start || + sbVamount != Amount || + sbVtotal != Total) + { + sbVstart = Start; + sbVamount = Amount; + sbVtotal = Total; + + if (View->Parent == 0) + return 0; + if (Amount < 1 || Start + Amount > Total) { + qView->vert->setRange(0, 0); + qView->vert->setSteps(0, 0); + qView->vert->setValue(0); + } else { + qView->vert->setRange(0, Total - Amount); + qView->vert->setSteps(1, Amount); + qView->vert->setValue(Start); + } + } + return 1; +} + +int GViewPeer::SetSbHPos(int Start, int Amount, int Total) { + if (sbHstart != Start || + sbHamount != Amount || + sbHtotal != Total) + { + sbHstart = Start; + sbHamount = Amount; + sbHtotal = Total; + + if (View->Parent == 0) + return 0; + + if (Amount < 1 || Start + Amount > Total) { + qView->horz->setRange(0, 0); + qView->horz->setSteps(0, 0); + qView->horz->setValue(0); + } else { + qView->horz->setRange(0, Total - Amount); + qView->horz->setSteps(1, Amount); + qView->horz->setValue(Start); + } + } + return 1; +} + +int GViewPeer::UpdateCursor() { + ConSetCursorPos(cX, cY); + ConSetCursorSize(cStart, cEnd); + if (cVisible) + ConShowCursor(); + else + ConHideCursor(); + return 1; +} + +int GViewPeer::PMShowCursor() { + return 1; +} + +int GViewPeer::PMHideCursor() { + return 1; +} + +int GViewPeer::PMSetCursorPos() { + return 1; +} + +/////////////////////////////////////////////////////////////////////////// + +GView::GView(GFrame *parent, int XSize, int YSize) { + Parent = parent; + Prev = Next = 0; + Peer = new GViewPeer(this, XSize, YSize); + if (Parent) + Parent->AddView(this); +} + +GView::~GView() { + if (Parent) + Parent->RemoveView(this); + if (Peer) + delete Peer; +} + +int GView::ConClear() { + int W, H; + TDrawBuffer B; + + ConQuerySize(&W, &H); + MoveChar(B, 0, W, ' ', 0x07, 1); + ConSetBox(0, 0, W, H, B[0]); + return 1; +} + +int GView::ConPutBox(int X, int Y, int W, int H, PCell Cell) { + return Peer->ConPutBox(X, Y, W, H, Cell); +} + +int GView::ConGetBox(int X, int Y, int W, int H, PCell Cell) { + return Peer->ConGetBox(X, Y, W, H, Cell); +} + +int GView::ConPutLine(int X, int Y, int W, int H, PCell Cell) { + return Peer->ConPutLine(X, Y, W, H, Cell); +} + +int GView::ConSetBox(int X, int Y, int W, int H, TCell Cell) { + return Peer->ConSetBox(X, Y, W, H, Cell); +} + +int GView::ConScroll(int Way, int X, int Y, int W, int H, TAttr Fill, int Count) { + return Peer->ConScroll(Way, X, Y, W, H, Fill, Count); +} + +int GView::ConSetSize(int X, int Y) { + if (Peer->ConSetSize(X, Y)) ; +// Resize(X, Y); + else + return 0; + return 1; +} + +int GView::ConQuerySize(int *X, int *Y) { + return Peer->ConQuerySize(X, Y); +} + +int GView::ConSetCursorPos(int X, int Y) { + return Peer->ConSetCursorPos(X, Y); +} + +int GView::ConQueryCursorPos(int *X, int *Y) { + return Peer->ConQueryCursorPos(X, Y); +} + +int GView::ConShowCursor() { + return Peer->ConShowCursor(); +} + +int GView::ConHideCursor() { + return Peer->ConHideCursor(); +} + +int GView::ConCursorVisible() { + return Peer->ConCursorVisible(); +} + +int GView::ConSetCursorSize(int Start, int End) { + return Peer->ConSetCursorSize(Start, End); +} + +int GView::QuerySbVPos() { + return Peer->QuerySbVPos(); +} + +int GView::SetSbVPos(int Start, int Amount, int Total) { + return Peer->SetSbVPos(Start, Amount, Total); +} + +int GView::SetSbHPos(int Start, int Amount, int Total) { + return Peer->SetSbHPos(Start, Amount, Total); +} + +int GView::ExpandHeight(int DeltaY) { + return Peer->ExpandHeight(DeltaY); +} + +void GView::Update() { +} + +void GView::Repaint() { +} + +void GView::HandleEvent(TEvent &Event) { +} + +void GView::Resize(int width, int height) { + Repaint(); +} + +void GView::EndExec(int NewResult) { + Result = NewResult; +} + +int GView::Execute() { + int SaveRc = Result; + int NewResult; + + Result = -2; + while (Result == -2 && frames != 0) + gui->ProcessEvent(); + NewResult = Result; + Result = SaveRc; + return NewResult; +} + +int GView::IsActive() { + return (Parent->Active == this); +} + +void GView::Activate(int gotfocus) { + if (gotfocus) { + Peer->wState |= sfFocus; + Peer->UpdateCursor(); + } else { + Peer->wState &= ~sfFocus; + } + Repaint(); +} + +int GView::CaptureMouse(int grab) { + if (MouseCapture == 0) { + if (grab) + MouseCapture = this; + else + return 0; + } else { + if (grab || MouseCapture != this) + return 0; + else + MouseCapture = 0; + } + return 1; +} + +/////////////////////////////////////////////////////////////////////////// + +GFramePeer::GFramePeer(GFrame *aFrame, int Width, int Height) { + Frame = aFrame; + qFrame = new QEFrame(this, 0, 0); + CHECK_PTR(qFrame); + + if (Width != -1 && Height != -1) + ConSetSize(Width, Height); +} + +GFramePeer::~GFramePeer() { + delete qFrame; +} + +int GFramePeer::ConSetSize(int X, int Y) { + //return ::ConSetSize(X, Y); + return 0; +} + +int GFramePeer::ConQuerySize(int *X, int *Y) { +// ::ConQuerySize(&fW, &fH); +// if (X) *X = fW; +// if (Y) *Y = fH; + return 1; +} + +//int GFrame::ConQuerySize(int *X, int *Y) { +// ::ConQuerySize(X, Y); +// if (ShowVScroll) +// --*X; +//} + +int GFramePeer::ConSetTitle(char *Title, char *STitle) { + qFrame->setCaption(Title); + qFrame->setIconText(STitle); + return 1; +} + +int GFramePeer::ConGetTitle(char *Title, int MaxLen, char *STitle, int SMaxLen) { + strncpy(Title, qFrame->caption(), MaxLen); + Title[MaxLen - 1] = 0; + strncpy(STitle, qFrame->iconText(), SMaxLen); + STitle[SMaxLen - 1] = 0; + return 1; +} + +void GFramePeer::MapFrame() { + qApp->setMainWidget(qFrame); + qFrame->menubar->show(); + + int menubarHeight = + qFrame->menubar->height(); + + qFrame->setMinimumSize(30 * cxChar + SCROLLBAR_SIZE + EDIT_BORDER * 2, + 8 * cyChar + SCROLLBAR_SIZE + EDIT_BORDER * 2 + + menubarHeight); + qFrame->setMaximumSize(160 * cxChar + SCROLLBAR_SIZE + EDIT_BORDER * 2, + 100 * cyChar + SCROLLBAR_SIZE + EDIT_BORDER * 2 + + menubarHeight); + + qFrame->resize(80 * cxChar + SCROLLBAR_SIZE + EDIT_BORDER * 2, + 40 * cyChar + SCROLLBAR_SIZE + EDIT_BORDER * 2 + + menubarHeight); + qFrame->show(); + + // qFrame->setSizeIncrement(cxChar, cyChar); + { + XSizeHints hints; + + hints.flags = PBaseSize | PResizeInc; + hints.width_inc = cxChar; + hints.height_inc = cyChar; + hints.base_width = SCROLLBAR_SIZE + EDIT_BORDER * 2; + hints.base_height = SCROLLBAR_SIZE + EDIT_BORDER * 2 + menubarHeight; + + XSetWMNormalHints(display, qFrame->winId(), &hints); + } +} + +void GFramePeer::ShowFrame() { + qFrame->show(); +} + +/////////////////////////////////////////////////////////////////////////// + +GFrame::GFrame(int XSize, int YSize) { + Menu = 0; + if (frames == 0) { + frames = Prev = Next = this; + } else { + Next = frames->Next; + Prev = frames; + frames->Next->Prev = this; + frames->Next = this; + frames = this; + } + Top = Active = 0; + Peer = new GFramePeer(this, XSize, YSize); +} + +GFrame::~GFrame() { + if (Peer) { + delete Peer; + Peer = 0; + } + if (Next == this) { + frames = 0; +// DEBUGX(("No more frames\x7\x7\n")); + } else { + Next->Prev = Prev; + Prev->Next = Next; + frames = Next; + } + Next = Prev = 0; +} + +int GFrame::ConSetTitle(char *Title, char *STitle) { + return Peer->ConSetTitle(Title, STitle); +} + +int GFrame::ConGetTitle(char *Title, int MaxLen, char *STitle, int SMaxLen) { + return Peer->ConGetTitle(Title, MaxLen, STitle, SMaxLen); +} + +int GFrame::ConSetSize(int X, int Y) { + return Peer->ConSetSize(X, Y); +} + +int GFrame::ConQuerySize(int *X, int *Y) { + return Peer->ConQuerySize(X, Y); +} + +int GFrame::ConSplitView(GView *view, GView *newview) { + int dmy; + + newview->Parent = this; +// newview->Peer->wX = 0; + ConQuerySize(&newview->Peer->wW, &dmy); +// newview->Peer->wY = view->Peer->wY + view->Peer->wH / 2; + newview->Peer->wH = view->Peer->wH - view->Peer->wH / 2; + view->Peer->wH /= 2; + InsertView(view, newview); + view->ConSetSize(view->Peer->wW, view->Peer->wH); + newview->ConSetSize(newview->Peer->wW, newview->Peer->wH); + return 0; +} + +int GFrame::ConCloseView(GView *view) { + return 0; +} + +int GFrame::ConResizeView(GView *view, int DeltaY) { + return 0; +} + +int GFrame::AddView(GView *view) { + if (Top != 0) { + return ConSplitView(Top, view); + } else { +// int W, H; + + view->Parent = this; + view->Prev = view->Next = 0; + +// view->Peer->wX = 0; +// view->Peer->wY = 0; +// ConQuerySize(&W, &H); +// view->ConSetSize(W, H); + InsertView(Top, view); + return 0; + } +} + +void GFrame::Update() { + GView *v = Active; + + UpdateMenu(); + while (v) { + v->Update(); + v = v->Next; + if (v == Active) + break; + } +} + +void GFrame::UpdateMenu() { +} + +void GFrame::Repaint() { + GView *v = Active; + + while (v) { + v->Repaint(); + v = v->Next; + if (v == Active) + break; + } +} + +void GFrame::InsertView(GView *Prev, GView *view) { + if (!view) return ; + if (Prev) { + view->Prev = Prev; + view->Next = Prev->Next; + Prev->Next = view; + view->Next->Prev = view; + } else { + view->Prev = view->Next = view; + Top = view; + } + if (Active == 0) { + Active = view; + Active->Activate(1); + } +} + +void GFrame::RemoveView(GView *view) { + if (!view) return ; + + if (Active == view) + Active->Activate(0); + if (view->Next == view) { + Top = Active = 0; + delete this; + } else { + view->Next->Prev = view->Prev; + view->Prev->Next = view->Next; + + if (Top == view) { + Top = view->Next; +// Top->Peer->wY -= view->Peer->wH; +// Top->ConSetSize(Top->Peer->wW, Top->Peer->wH + view->Peer->wH); + } else { +// view->Prev->ConSetSize(view->Prev->Peer->wW, +// view->Prev->Peer->wH + view->Peer->wH); + } + + if (Active == view) { + Active = view->Prev; + Active->Activate(1); + } + } +} + +void GFrame::SelectNext(int back) { + GView *c = Active; + + if (c == 0 && Top == 0) + return; + else if (c == 0) + c = Active = Top; + else + if (back) { + Active = Active->Prev; + } else { + Active = Active->Next; + } + if (c != Active) { + c->Activate(0); + Active->Activate(1); + } + //if (Active) + // XtSetKeyboardFocus(Peer->PanedWin, Active->Peer->TextWin); +} + +int GFrame::SelectView(GView *view) { + if (Top == 0) + return 0; + + if (FocusCapture != 0 || MouseCapture != 0) + return 0; + + if (Active) + Active->Activate(0); + Active = view; + if (Active) + Active->Activate(1); + //if (Active) + // XtSetKeyboardFocus(Peer->PanedWin, Active->Peer->TextWin); + return 1; +} + +void GFrame::Resize(int width, int height) { + if (!Top) + return; + + if (width < 8 || height < 2) + return; + + if (Top == Top->Next) { + Top->ConSetSize(width, height); + } else { + } +} + +void GFrame::Show() { + Update(); + Peer->MapFrame(); +} + +void GFrame::Activate() { + frames = this; + Update(); + Peer->ShowFrame(); +} + +QPopupMenu *QEFrame::CreatePopup(QWidget *parent, int Id, int do_connect) { + QPopupMenu *menu = new QPopupMenu(parent); + CHECK_PTR(menu); + + //menu->setFont(QFont("Helvetica", 12, QFont::Bold)); + for (int i = 0; i < Menus[Id].Count; i++) { + if (Menus[Id].Items[i].Name) { + //puts(Menus[Id].Items[i].Name); + if (Menus[Id].Items[i].SubMenu != -1) { + QPopupMenu *submenu = + CreatePopup(0, + Menus[Id].Items[i].SubMenu, 0); + CHECK_PTR(submenu); + + menu->insertItem(Menus[Id].Items[i].Name, + submenu); + } else { + menu->insertItem(Menus[Id].Items[i].Name, + Menus[Id].Items[i].Cmd); + } + } else { + menu->insertSeparator(); + } + } + if (do_connect) + connect(menu, SIGNAL(activated(int)), SLOT(selectedMain(int))); + return menu; +} + +QMenuBar *QEFrame::CreateMenuBar(QWidget *parent, int Id) { + QMenuBar *menu = new QMenuBar(parent); + CHECK_PTR(menu); + + //menu->setFont(QFont("Helvetica", 12, QFont::Bold)); + for (int i = 0; i < Menus[Id].Count; i++) { + if (Menus[Id].Items[i].Name) { + //puts(Menus[Id].Items[i].Name); + + if (Menus[Id].Items[i].SubMenu != -1) { + QPopupMenu *submenu = + CreatePopup(0, + Menus[Id].Items[i].SubMenu, 0); + CHECK_PTR(submenu); + + menu->insertItem(Menus[Id].Items[i].Name, + submenu); + } else { + menu->insertItem(Menus[Id].Items[i].Name, + Menus[Id].Items[i].Cmd); + } + } else { + menu->insertSeparator(); + } + } + connect(menu, SIGNAL(activated(int)), SLOT(selectedMain(int))); + return menu; +} + +int GFrame::SetMenu(const char *Name) { + int id = GetMenuId(Name); + + if (Menu) + free(Menu); + Menu = strdup(Name); + + if (Peer->qFrame->menubar) { + delete Peer->qFrame->menubar; + Peer->qFrame->menubar = 0; + } + + DEBUGX(("setting main menu: %s, id=%d\n", Name, id)); + Peer->qFrame->menubar = Peer->qFrame->CreateMenuBar(Peer->qFrame, id); + //Peer->qFrame->menubar->setFrameStyle(QFrame::Raised | QFrame::Panel); + //Peer->qFrame->menubar->setLineWidth(1); + Peer->qFrame->menubar->show(); + return 1; +} + +int GFrame::ExecMainMenu(char Sub) { + return 0; +} + +int GFrame::PopupMenu(const char *Name) { + int id = GetMenuId(Name); + + QPopupMenu *popup = Peer->qFrame->CreatePopup(0, id, 1); + popup->popup(LastMousePos); + return 1; +} + +void QEFrame::timerDone() { + FinalExit = 0; + qApp->exit_loop(); +} + +// GUI + + +GUI::GUI(int &argc, char **argv, int XSize, int YSize) { + + fArgc = argc; + fArgv = argv; + + new QApplication(argc, argv); + + display = qt_xdisplay(); + + char *fs = getenv("VIOFONT"); + fontStruct = NULL; + if (fs == 0 && WindowFont[0] != 0) + fs = WindowFont; + if (fs) + fontStruct = XLoadQueryFont(display, fs); + if (fontStruct == NULL) + fontStruct = XLoadQueryFont(display, "8x13"); + if (fontStruct == NULL) + fontStruct = XLoadQueryFont(display, "fixed"); + if (fontStruct == NULL) + return ; + + cxChar = fontStruct->max_bounds.width; + cyChar = fontStruct->max_bounds.ascent + fontStruct->max_bounds.descent; + + gui = this; +} + +GUI::~GUI() { + gui = 0; +} + +int GUI::ConGrabEvents(TEventMask EventMask) { + return 0; +} + +void GUI::DispatchEvent(GFrame *frame, GView *view, TEvent &Event) { + if (Event.What != evNone) { + if (view) + view->HandleEvent(Event); + } +} + +int GUI::ConSuspend(void) { return 0; } + +int GUI::ConContinue(void) { return 0; } + +int GUI::ConGetEvent(TEventMask EventMask, TEvent *Event, int WaitTime, int Delete, GView **view) { + //return ::ConGetEvent(EventMask, Event, WaitTime, Delete, view); + assert(1 == 0); + return 0; +} + +int GUI::ConPutEvent(TEvent Event) { + EventBuf = Event; + return 0; +} + +int GUI::ConFlush(void) { + return 0; +} + +void GUI::ProcessEvent() { + static int need_update = 1; + + /* should process until no more events, + * but this is close enough */ + + if (need_update) + QTimer::singleShot(10, frames->Peer->qFrame, SLOT(timerDone())); + + FinalExit = 1; + NextEvent.What = evNone; + qApp->enter_loop(); + if (FinalExit && NextEvent.What == evNone) { + DEBUGX(("Final exit\n")); + //delete frames; + //frames = 0; + //return ; + } + + if (need_update) { + DEBUGX(("Updating\n")); + frames->Update(); + need_update = 0; + } + while (doLoop && qHasEvent()) { + NextEvent.What = evNone; + qGetEvent(NextEvent); + DEBUGX(("Got event: %d\n", NextEvent.What)); + if (NextEvent.What == evMouseDown) { + DEBUGX(("x:%d, y:%d, buttons:%d\n", + NextEvent.Mouse.X, + NextEvent.Mouse.Y, + NextEvent.Mouse.Buttons)); + } + DispatchEvent(frames, NextEvent.Msg.View, NextEvent); + NextEvent.What = evNone; + need_update = 1; + } +} + +int GUI::Run() { + if (Start(fArgc, fArgv) == 0) { + doLoop = 1; + frames->Show(); + + while (doLoop) + ProcessEvent(); + + Stop(); + return 0; + } + return 1; +} + +int GUI::ShowEntryScreen() { + return 1; +} + +int GUI::RunProgram(char *Command) { + char Cmd[1024]; + + char* xterm = getenv("TERM"); + if (NULL == xterm || 0 == *xterm) + xterm = "xterm"; + + strcpy(Cmd, xterm); + + if (*Command == 0) // empty string = shell + strcat(Cmd, " -ls &"); + else { + strcat(Cmd, " -e "); + // buffer overflow problem: -2 for possible async. + strncat(Cmd, Command, sizeof(Cmd) - strlen(Cmd) - 2); + Cmd[sizeof(Cmd) - 3] = 0; + if (mode == RUN_ASYNC) + strcat(Cmd, " &"); + } + rc = system(Cmd); + return rc; +} + +/*void PipeCallback(GPipe *pipe, int *source, int *input) { + if (pipe && pipe->notify && *source == pipe->fd) { + NextEvent.What = evNotify; + NextEvent.Msg.View = frames->Active; + NextEvent.Msg.Model = pipe->notify; + NextEvent.Msg.Command = cmPipeRead; + NextEvent.Msg.Param1 = pipe->id; + pipe->stopped = 0; + } + DEBUGX(("Pipe %d\n", *source)); +} + */ +int GUI::OpenPipe(char *Command, EModel *notify) { + int i; + + for (i = 0; i < MAX_PIPES; i++) { + if (Pipes[i].used == 0) { + int pfd[2]; + + Pipes[i].id = i; + Pipes[i].notify = notify; + Pipes[i].stopped = 1; + + if (pipe((int *)pfd) == -1) + return -1; + + switch (Pipes[i].pid = fork()) { + case -1: /* fail */ + return -1; + case 0: /* child */ + close(pfd[0]); + close(0); + dup2(pfd[1], 1); + dup2(pfd[1], 2); + exit(system(Command)); + default: + close(pfd[1]); + fcntl(pfd[0], F_SETFL, O_NONBLOCK); + Pipes[i].fd = pfd[0]; + } + //Pipes[i].input = + // XtAppAddInput(AppContext, Pipes[i].fd, XtInputReadMask, PipeCallback, &Pipes[i]); + Pipes[i].used = 1; + DEBUGX(("Pipe Open: %d\n", i)); + return i; + } + } + return -1; +} + +int GUI::SetPipeView(int id, EModel *notify) { + if (id < 0 || id > MAX_PIPES) + return -1; + if (Pipes[id].used == 0) + return -1; + DEBUGX(("Pipe View: %d %08X\n", id, notify)); + Pipes[id].notify = notify; + if (notify != Pipes[id].notify) + if (notify) { + //Pipes[id].input = + // XtAppAddInput(AppContext, Pipes[id].fd, XtInputReadMask, PipeCallback, &Pipes[id]); + } else { + //if (Pipes[id].input != 0) { + // XtRemoveInput(Pipes[id].input); + // Pipes[id].input = 0; + //} + } + return 0; +} + +int GUI::ReadPipe(int id, void *buffer, int len) { + int rc; + + if (id < 0 || id > MAX_PIPES) + return -1; + if (Pipes[id].used == 0) + return -1; + DEBUGX(("Pipe Read: Get %d %d\n", id, len)); + + rc = read(Pipes[id].fd, buffer, len); + DEBUGX(("Pipe Read: Got %d %d\n", id, len)); + if (rc == 0) { + //if (Pipes[id].input != 0) { + //XtRemoveInput(Pipes[id].input); + // Pipes[id].input = 0; + // } + close(Pipes[id].fd); + return -1; + } + if (rc == -1) { + Pipes[id].stopped = 1; + return 0; + } + return rc; +} + +int GUI::ClosePipe(int id) { + int status; + + if (id < 0 || id > MAX_PIPES) + return -1; + if (Pipes[id].used == 0) + return -1; + waitpid(Pipes[id].pid, &status, 0); + DEBUGX(("Pipe Close: %d\n", id)); + Pipes[id].used = 0; + return WEXITSTATUS(status); +} + +int GUI::multiFrame() { return 1; } + +int GetXSelection(int *len, char **data) { + QClipboard *cb = QApplication::clipboard(); + const char *text; + + text = cb->text(); + if (text == 0) + return -1; + + *len = strlen(text); + *data = (char *)malloc(*len); + if (*data == 0) + return -1; + memcpy(*data, text, *len); + return 0; +} + +int SetXSelection(int len, char *data) { + QClipboard *cb = QApplication::clipboard(); + char *text = (char *)malloc(len + 1); + if (text == 0) + return -1; + memcpy(text, data, len); + text[len] = 0; + free(text); + return 0; +} + +void DieError(int rc, const char *msg, ...) { + va_list ap; + + va_start(ap, msg); + vfprintf(stderr, msg, ap); + va_end(ap); + exit(rc); +} + +char ConGetDrawChar(int index) { + static char tab[] = "\x0D\x0C\x0E\x0B\x12\x19____+>\x1F\x01\x12 "; + + assert(index >= 0 && index < strlen(tab)); + + return tab[index]; +} diff --git a/src/g_qt.moc b/src/g_qt.moc new file mode 100644 index 0000000..54f63bf --- /dev/null +++ b/src/g_qt.moc @@ -0,0 +1,129 @@ +/**************************************************************************** +** QEText meta object code from reading C++ file 'g_qt.cpp' +** +** Created: Sat May 23 17:43:55 1998 +** by: The Qt Meta Object Compiler ($Revision: 1.1.1.1 $) +** +** WARNING! All changes made in this file will be lost! +*****************************************************************************/ + +#if !defined(Q_MOC_OUTPUT_REVISION) +#define Q_MOC_OUTPUT_REVISION 2 +#elif Q_MOC_OUTPUT_REVISION != 2 +#error Moc format conflict - please regenerate all moc files +#endif + +#include + + +const char *QEText::className() const +{ + return "QEText"; +} + +QMetaObject *QEText::metaObj = 0; + +void QEText::initMetaObject() +{ + if ( metaObj ) + return; + if ( strcmp(QWidget::className(), "QWidget") != 0 ) + badSuperclassWarning("QEText","QWidget"); + if ( !QWidget::metaObject() ) + QWidget::initMetaObject(); + metaObj = new QMetaObject( "QEText", "QWidget", + 0, 0, + 0, 0 ); +} + + +const char *QEView::className() const +{ + return "QEView"; +} + +QMetaObject *QEView::metaObj = 0; + +void QEView::initMetaObject() +{ + if ( metaObj ) + return; + if ( strcmp(QFrame::className(), "QFrame") != 0 ) + badSuperclassWarning("QEView","QFrame"); + if ( !QFrame::metaObject() ) + QFrame::initMetaObject(); + typedef void(QEView::*m1_t0)(); + typedef void(QEView::*m1_t1)(); + typedef void(QEView::*m1_t2)(); + typedef void(QEView::*m1_t3)(); + typedef void(QEView::*m1_t4)(int); + typedef void(QEView::*m1_t5)(); + typedef void(QEView::*m1_t6)(); + typedef void(QEView::*m1_t7)(); + typedef void(QEView::*m1_t8)(); + typedef void(QEView::*m1_t9)(int); + m1_t0 v1_0 = &QEView::sbHmoveLeft; + m1_t1 v1_1 = &QEView::sbHmoveRight; + m1_t2 v1_2 = &QEView::sbHpageLeft; + m1_t3 v1_3 = &QEView::sbHpageRight; + m1_t4 v1_4 = &QEView::sbHmoveTo; + m1_t5 v1_5 = &QEView::sbVmoveUp; + m1_t6 v1_6 = &QEView::sbVmoveDown; + m1_t7 v1_7 = &QEView::sbVpageUp; + m1_t8 v1_8 = &QEView::sbVpageDown; + m1_t9 v1_9 = &QEView::sbVmoveTo; + QMetaData *slot_tbl = new QMetaData[10]; + slot_tbl[0].name = "sbHmoveLeft()"; + slot_tbl[1].name = "sbHmoveRight()"; + slot_tbl[2].name = "sbHpageLeft()"; + slot_tbl[3].name = "sbHpageRight()"; + slot_tbl[4].name = "sbHmoveTo(int)"; + slot_tbl[5].name = "sbVmoveUp()"; + slot_tbl[6].name = "sbVmoveDown()"; + slot_tbl[7].name = "sbVpageUp()"; + slot_tbl[8].name = "sbVpageDown()"; + slot_tbl[9].name = "sbVmoveTo(int)"; + slot_tbl[0].ptr = *((QMember*)&v1_0); + slot_tbl[1].ptr = *((QMember*)&v1_1); + slot_tbl[2].ptr = *((QMember*)&v1_2); + slot_tbl[3].ptr = *((QMember*)&v1_3); + slot_tbl[4].ptr = *((QMember*)&v1_4); + slot_tbl[5].ptr = *((QMember*)&v1_5); + slot_tbl[6].ptr = *((QMember*)&v1_6); + slot_tbl[7].ptr = *((QMember*)&v1_7); + slot_tbl[8].ptr = *((QMember*)&v1_8); + slot_tbl[9].ptr = *((QMember*)&v1_9); + metaObj = new QMetaObject( "QEView", "QFrame", + slot_tbl, 10, + 0, 0 ); +} + + +const char *QEFrame::className() const +{ + return "QEFrame"; +} + +QMetaObject *QEFrame::metaObj = 0; + +void QEFrame::initMetaObject() +{ + if ( metaObj ) + return; + if ( strcmp(QFrame::className(), "QFrame") != 0 ) + badSuperclassWarning("QEFrame","QFrame"); + if ( !QFrame::metaObject() ) + QFrame::initMetaObject(); + typedef void(QEFrame::*m1_t0)(int); + typedef void(QEFrame::*m1_t1)(); + m1_t0 v1_0 = &QEFrame::selectedMain; + m1_t1 v1_1 = &QEFrame::timerDone; + QMetaData *slot_tbl = new QMetaData[2]; + slot_tbl[0].name = "selectedMain(int)"; + slot_tbl[1].name = "timerDone()"; + slot_tbl[0].ptr = *((QMember*)&v1_0); + slot_tbl[1].ptr = *((QMember*)&v1_1); + metaObj = new QMetaObject( "QEFrame", "QFrame", + slot_tbl, 2, + 0, 0 ); +} diff --git a/src/g_qt_dlg.cpp b/src/g_qt_dlg.cpp new file mode 100644 index 0000000..cbddd24 --- /dev/null +++ b/src/g_qt_dlg.cpp @@ -0,0 +1,214 @@ +#include +#include +#include +#include +#include +#include + +#include "sysdep.h" +#include "console.h" +#include "gui.h" +#include "s_files.h" + +#include +#include +#include +#include +#include +#include +#include + +#define DEBUGX(x) // printf x + +unsigned long HaveGUIDialogs = GUIDLG_FILE | GUIDLG_CHOICE; + +int DLGGetFile(GView *v, const char *Prompt, unsigned int BufLen, char *FileName, int Flags) { + QString fn; + char filter[MAXPATH] = "*"; + char directory[MAXPATH]; + + assert(BufLen > 0); + + JustDirectory(FileName, directory); + + DEBUGX(("Doing file dialog\n")); + if (Flags & GF_SAVEAS) { + fn = QFileDialog::getSaveFileName(directory, filter); + } else { + fn = QFileDialog::getOpenFileName(directory, filter); + } + DEBUGX(("File dialog done\n")); + if (fn.isNull()) + return 0; + strncpy(FileName, fn, BufLen); + FileName[BufLen - 1] = 0; + DEBUGX(("selected %s\n", FileName)); + return FileName[0] ? 1 : 0; +} + +const int kMaxButton = 16; + +class QChoiceBox : public QDialog { + Q_OBJECT +public: + QChoiceBox(QWidget *parent=0, const char *name=0); + + void setText(const char *text); + void addButton(const char *text); + + void adjustSize(); + + int getChoice() { return buttonActivated; } + +public slots: + void pressed(); + void released(); + void clicked(); + +protected: + void resizeEvent(QResizeEvent *); + +private: + QLabel *label; + QPushButton *button[kMaxButton]; + int buttonCount; + int buttonArmed; + int buttonSelected; + int buttonActivated; + void *reserved1; + void *reserved2; +}; + + +QChoiceBox::QChoiceBox(QWidget *parent, const char *name) + : QDialog(parent, name, TRUE) +{ + initMetaObject(); + + buttonSelected = -1; + buttonCount = 0; + buttonActivated = -1; + buttonArmed = -1; + + label = new QLabel(this, "text"); + CHECK_PTR(label); + label->setAlignment(AlignLeft); + QFont font("Helvetica", 12, QFont::Bold); + label->setFont(font ); +} + +void QChoiceBox::setText(const char *text) { + label->setText(text); +} + +void QChoiceBox::addButton(const char *text) { + assert(buttonCount < kMaxButton); + + button[buttonCount] = new QPushButton(this); + CHECK_PTR(button[buttonCount]); + connect(button[buttonCount], SIGNAL(clicked()), SLOT(clicked())); + connect(button[buttonCount], SIGNAL(pressed()), SLOT(pressed())); + connect(button[buttonCount], SIGNAL(released()), SLOT(released())); + button[buttonCount]->setFont(QFont("Helvetica", 12, QFont::Bold)); + button[buttonCount]->setText(text ? text : "?" ); + buttonCount++; +} + +void QChoiceBox::adjustSize() { + int w_buttons = 0; + + for (int i = 0; i < buttonCount; i++) { + button[i]->adjustSize(); + w_buttons += button[i]->width() + 10; + } + + label->adjustSize(); + + QString labelStr = label->text(); + int nlines = labelStr.contains('\n'); + QFontMetrics fm = label->fontMetrics(); + nlines += 2; + int w = QMAX(w_buttons, label->width()); + int h = button[0]->height() + fm.lineSpacing()*nlines; + resize( w + w/3, h + h/3 ); +} + +void QChoiceBox::resizeEvent( QResizeEvent * ) { + int i; + + for (i = 0; i < buttonCount; i++) { + button[i]->adjustSize(); + } + label->adjustSize(); + int h = (height() - button[0]->height() - label->height())/3; + int x = 10; + + for (i = 0; i < buttonCount; i++) { + button[i]->move(x, height() - h - button[i]->height()); + x += button[i]->width() + 10; + } + label->move( 10, h ); +} + +void QChoiceBox::pressed() { + int i; + + buttonSelected = -1; + for (i = 0; i < buttonCount; i++) + if (button[i]->isDown()) + buttonSelected = i; + buttonArmed = buttonSelected; + DEBUGX(("selected: %d\n", buttonSelected)); +} + +void QChoiceBox::released() { + buttonSelected = -1; + DEBUGX(("released\n")); +} + +void QChoiceBox::clicked() { + buttonActivated = buttonArmed; + DEBUGX(("activated: %d\n", buttonActivated)); + accept(); +} + +#include "g_qt_dlg.moc" + +int DLGPickChoice(GView *v, char *ATitle, int NSel, va_list ap, int Flags) { + QChoiceBox *cb = new QChoiceBox(); + CHECK_PTR(cb); + cb->setCaption( ATitle ); + + for (int i = 0; i < NSel; i++) + cb->addButton(va_arg(ap, char *)); + + char msg[1024]; + char *fmt; + fmt = va_arg(ap, char *); + vsprintf(msg, fmt, ap); + + cb->setText(msg); + + int retcode = cb->exec(); + + delete cb; + if (retcode == QDialog::Accepted) + return cb->getChoice(); + return -1; +} + +int DLGGetFind(GView *View, SearchReplaceOptions &sr) { + assert(1==0); + return 0; +} + +int DLGGetFindReplace(GView *View, SearchReplaceOptions &sr) { + assert(1==0); + return 0; +} + +int DLGGetStr(GView *View, char *Prompt, unsigned int BufLen, char *Str, int HistId, int Flags) { + assert(1 == 0); + return 0; +} + diff --git a/src/g_qt_dlg.moc b/src/g_qt_dlg.moc new file mode 100644 index 0000000..54a0829 --- /dev/null +++ b/src/g_qt_dlg.moc @@ -0,0 +1,50 @@ +/**************************************************************************** +** QChoiceBox meta object code from reading C++ file 'g_qt_dlg.cpp' +** +** Created: Sat May 23 17:42:27 1998 +** by: The Qt Meta Object Compiler ($Revision: 1.1.1.1 $) +** +** WARNING! All changes made in this file will be lost! +*****************************************************************************/ + +#if !defined(Q_MOC_OUTPUT_REVISION) +#define Q_MOC_OUTPUT_REVISION 2 +#elif Q_MOC_OUTPUT_REVISION != 2 +#error Moc format conflict - please regenerate all moc files +#endif + +#include + + +const char *QChoiceBox::className() const +{ + return "QChoiceBox"; +} + +QMetaObject *QChoiceBox::metaObj = 0; + +void QChoiceBox::initMetaObject() +{ + if ( metaObj ) + return; + if ( strcmp(QDialog::className(), "QDialog") != 0 ) + badSuperclassWarning("QChoiceBox","QDialog"); + if ( !QDialog::metaObject() ) + QDialog::initMetaObject(); + typedef void(QChoiceBox::*m1_t0)(); + typedef void(QChoiceBox::*m1_t1)(); + typedef void(QChoiceBox::*m1_t2)(); + m1_t0 v1_0 = &QChoiceBox::pressed; + m1_t1 v1_1 = &QChoiceBox::released; + m1_t2 v1_2 = &QChoiceBox::clicked; + QMetaData *slot_tbl = new QMetaData[3]; + slot_tbl[0].name = "pressed()"; + slot_tbl[1].name = "released()"; + slot_tbl[2].name = "clicked()"; + slot_tbl[0].ptr = *((QMember*)&v1_0); + slot_tbl[1].ptr = *((QMember*)&v1_1); + slot_tbl[2].ptr = *((QMember*)&v1_2); + metaObj = new QMetaObject( "QChoiceBox", "QDialog", + slot_tbl, 3, + 0, 0 ); +} diff --git a/src/g_text.cpp b/src/g_text.cpp new file mode 100644 index 0000000..3c77d4e --- /dev/null +++ b/src/g_text.cpp @@ -0,0 +1,1232 @@ +/* g_text.cpp + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#include +#include +#include +#include +#include +#include + +#include "console.h" +#include "gui.h" +#include "c_mode.h" +#include "c_color.h" + +#if defined(_DEBUG) && defined(MSVC) && defined(MSVCDEBUG) +#include + +#define new new( _CLIENT_BLOCK, __FILE__, __LINE__) + +#endif //_DEBUG && MSVC && MSVCDEBUG + + +int ShowVScroll = 1; +int ShowHScroll = 1; +int ShowMenuBar = 1; +int ShowToolBar = 0; +unsigned long HaveGUIDialogs = 0; // no gui dialogs in text gui + +GFrame *frames = 0; +GUI *gui = 0; + +GView *MouseCapture = 0; +GView *FocusCapture = 0; + +TEvent NextEvent = { 0 }; + +#define sfFocus 1 + +class UpMenu; + +extern int ExecMainMenu(TEvent &E, char sub); +extern int ExecVertMenu(int x, int y, int id, TEvent &E, UpMenu *up); + +class GViewPeer { +public: + GView *View; + int wX, wY, wW, wH, wState; + int cX, cY, cVisible, cStart, cEnd; + int sbVstart, sbVamount, sbVtotal, sbVupdate; + int sbHstart, sbHamount, sbHtotal, sbHupdate; + int SbVBegin, SbVEnd, SbHBegin, SbHEnd; + + GViewPeer(GView *view, int XSize, int YSize); + ~GViewPeer(); + + int ConPutBox(int X, int Y, int W, int H, PCell Cell); + int ConGetBox(int X, int Y, int W, int H, PCell Cell); + int ConPutLine(int X, int Y, int W, int H, PCell Cell); + int ConSetBox(int X, int Y, int W, int H, TCell Cell); + int ConScroll(int Way, int X, int Y, int W, int H, TAttr Fill, int Count); + + int ConSetSize(int X, int Y); + int ConQuerySize(int *X, int *Y); + + int ConSetCursorPos(int X, int Y); + int ConQueryCursorPos(int *X, int *Y); + int ConShowCursor(); + int ConHideCursor(); + int ConCursorVisible(); + int ConSetCursorSize(int Start, int End); + + int CaptureMouse(int grab); + int CaptureFocus(int grab); + + int QuerySbVPos(); + int SetSbVPos(int Start, int Amount, int Total); + int SetSbHPos(int Start, int Amount, int Total); + int ExpandHeight(int DeltaY); + + int DrawScrollBar(); + int UpdateCursor(); +}; + +class GFramePeer { +public: + int fW, fH; + GFrame *Frame; + + GFramePeer(GFrame *aFrame, int Width, int Height); + ~GFramePeer(); + + int ConSetTitle(char *Title, char *STitle); + int ConGetTitle(char *Title, int MaxLen, char *STitle, int SMaxLen); + + int ConSetSize(int X, int Y); + int ConQuerySize(int *X, int *Y); + +}; + +/////////////////////////////////////////////////////////////////////////// + +GViewPeer::GViewPeer(GView *view, int XSize, int YSize) { + View = view; + wX = 0; + wY = 0; + wW = XSize; + wH = YSize; + sbVtotal = 0; + sbVstart = 0; + sbVamount = 0; + sbVupdate = 1; + sbHtotal = 0; + sbHstart = 0; + sbHamount = 0; + sbHupdate = 1; + wState = 0; + cVisible = 1; + cStart = 0; // % + cEnd = 100; + cX = cY = 0; +} + +GViewPeer::~GViewPeer() { + if (MouseCapture == View) + MouseCapture = 0; + if (FocusCapture == View) + FocusCapture = 0; +} + +int GViewPeer::ConPutBox(int X, int Y, int W, int H, PCell Cell) { + return ::ConPutBox(X + wX, Y + wY, W, H, Cell); +} + +int GViewPeer::ConGetBox(int X, int Y, int W, int H, PCell Cell) { + return ::ConGetBox(X + wX, Y + wY, W, H, Cell); +} + +int GViewPeer::ConPutLine(int X, int Y, int W, int H, PCell Cell) { + return ::ConPutLine(X + wX, Y + wY, W, H, Cell); +} + +int GViewPeer::ConSetBox(int X, int Y, int W, int H, TCell Cell) { + return ::ConSetBox(X + wX, Y + wY, W, H, Cell); +} + +int GViewPeer::ConScroll(int Way, int X, int Y, int W, int H, TAttr Fill, int Count) { + return ::ConScroll(Way, X + wX, Y + wY, W, H, Fill, Count); +} + +int GViewPeer::ConSetSize(int X, int Y) { + wW = X; + wH = Y; + return 1; +} + +int GViewPeer::ConQuerySize(int *X, int *Y) { + if (X) *X = wW; + if (Y) *Y = wH; + return 1; +} + +int GViewPeer::ConSetCursorPos(int X, int Y) { + if (X < 0) X = 0; + if (X >= wW) X = wW - 1; + if (Y < 0) Y = 0; + if (Y >= wH) Y = wH - 1; + cX = X; + cY = Y; + if (wState & sfFocus) + return ::ConSetCursorPos(cX + wX, cY + wY); + else + return 1; +} + +int GViewPeer::ConQueryCursorPos(int *X, int *Y) { + if (X) *X = cX; + if (Y) *Y = cY; + return 1; +} + +int GViewPeer::ConShowCursor() { + cVisible = 1; + if (wState & sfFocus) + return ::ConShowCursor(); + else + return 1; +} + +int GViewPeer::ConHideCursor() { + cVisible = 0; + if (wState & sfFocus) + return ::ConHideCursor(); + else + return 1; +} + +int GViewPeer::ConCursorVisible() { + return cVisible; +} + +int GViewPeer::ConSetCursorSize(int Start, int End) { + cStart = Start; + cEnd = End; + if (wState & sfFocus) + return ::ConSetCursorSize(Start, End); + else + return 1; +} + +int GViewPeer::CaptureMouse(int grab) { + if (MouseCapture == 0) { + if (grab) + MouseCapture = View; + else + return 0; + } else { + if (grab || MouseCapture != View) + return 0; + else + MouseCapture = 0; + } + return 1; +} + +int GViewPeer::CaptureFocus(int grab) { + if (FocusCapture == 0) { + if (grab) + FocusCapture = View; + else + return 0; + } else { + if (grab || FocusCapture != View) + return 0; + else + FocusCapture = 0; + } + return 1; +} + +int GViewPeer::ExpandHeight(int DeltaY) { + if (View->Parent->Top == View->Next) + return -1; + if (DeltaY + wH < 3) + DeltaY = - (wH - 3); + if (View->Next->Peer->wH - DeltaY < 3) + DeltaY = View->Next->Peer->wH - 3; + View->Peer->ConSetSize(wW, wH + DeltaY); + View->Next->Peer->wY += DeltaY; + View->Next->Peer->ConSetSize(View->Next->Peer->wW, View->Next->Peer->wH - DeltaY); + View->Resize(View->Peer->wW, View->Peer->wH); + View->Next->Resize(View->Next->Peer->wW, View->Next->Peer->wH); + return 0; +} + +int GViewPeer::QuerySbVPos() { + return sbVstart; +} + +int GViewPeer::SetSbVPos(int Start, int Amount, int Total) { + if (sbVstart != Start || + sbVamount != Amount || + sbVtotal != Total) + { + sbVstart = Start; + sbVamount = Amount; + sbVtotal = Total; + sbVupdate = 1; +// DrawScrollBar(); + } + return 1; +} + +int GViewPeer::SetSbHPos(int Start, int Amount, int Total) { + if (sbHstart != Start || + sbHamount != Amount || + sbHtotal != Total) + { + sbHstart = Start; + sbHamount = Amount; + sbHtotal = Total; + sbHupdate = 1; +// DrawScrollBar(); + } + return 1; +} + +int GViewPeer::UpdateCursor() { + ConSetCursorPos(cX, cY); + ConSetCursorSize(cStart, cEnd); + if (cVisible) + ConShowCursor(); + else + ConHideCursor(); + return 0; +} + +int GViewPeer::DrawScrollBar() { + TDrawBuffer B; + int NRows, NCols, I; + int W, H; + char fore = ConGetDrawChar(DCH_HFORE); + char back = ConGetDrawChar(DCH_HBACK); + + ConQuerySize(&W, &H); + + if (ShowVScroll) { + MoveCh(B, ConGetDrawChar(DCH_AUP), hcScrollBar_Arrows, 1); + ConPutBox(W, 0, 1, 1, B); + MoveCh(B, ConGetDrawChar(DCH_ADOWN), hcScrollBar_Arrows, 1); + ConPutBox(W, H - 1, 1, 1, B); + + NRows = H - 2; + + if (sbVtotal <= NRows) { + SbVBegin = 0; + SbVEnd = NRows - 1; + } else { + SbVBegin = NRows * sbVstart / sbVtotal; + SbVEnd = SbVBegin + NRows * sbVamount / sbVtotal; + } + + for (I = 0; I < NRows; I++) { + if (I >= SbVBegin && I <= SbVEnd) + MoveCh(B, fore, hcScrollBar_Fore, 1); + else + MoveCh(B, back, hcScrollBar_Back, 1); + ConPutBox(W, I + 1, 1, 1, B); + } + } + if (ShowHScroll) { + MoveCh(B, ConGetDrawChar(DCH_ALEFT), hcScrollBar_Arrows, 1); + ConPutBox(0, H, 1, 1, B); + MoveCh(B, ConGetDrawChar(DCH_ARIGHT), hcScrollBar_Arrows, 1); + ConPutBox(W - 1, H, 1, 1, B); + + NCols = W - 2; + + if (sbHtotal <= NCols) { + SbHBegin = 0; + SbHEnd = NCols - 1; + } else { + SbHBegin = NCols * sbHstart / sbHtotal; + SbHEnd = SbHBegin + NCols * sbHamount / sbHtotal; + } + + // could be made faster + for (I = 0; I < NCols; I++) { + if (I >= SbHBegin && I <= SbHEnd) + MoveCh(B, fore, hcScrollBar_Fore, 1); + else + MoveCh(B, back, hcScrollBar_Back, 1); + ConPutBox(I + 1, H, 1, 1, B); + } + } + if (ShowVScroll && ShowHScroll) { + MoveCh(B, ' ', hcScrollBar_Arrows, 1); + ConPutBox(W, H, 1, 1, B); + } + + return 0; +} + + +/////////////////////////////////////////////////////////////////////////// + +GView::GView(GFrame *parent, int XSize, int YSize) { + Parent = parent; + Prev = Next = 0; + Peer = new GViewPeer(this, XSize, YSize); + if (Parent) + Parent->AddView(this); +} + +GView::~GView() { + if (Parent) + Parent->RemoveView(this); + delete Peer; +} + +int GView::ConClear() { + int W, H; + TDrawBuffer B; + + ConQuerySize(&W, &H); + MoveChar(B, 0, W, ' ', 0x07, 1); + ConSetBox(0, 0, W, H, B[0]); + return 1; +} + +int GView::ConPutBox(int X, int Y, int W, int H, PCell Cell) { + return Peer->ConPutBox(X, Y, W, H, Cell); +} + +int GView::ConGetBox(int X, int Y, int W, int H, PCell Cell) { + return Peer->ConGetBox(X, Y, W, H, Cell); +} + +int GView::ConPutLine(int X, int Y, int W, int H, PCell Cell) { + return Peer->ConPutLine(X, Y, W, H, Cell); +} + +int GView::ConSetBox(int X, int Y, int W, int H, TCell Cell) { + return Peer->ConSetBox(X, Y, W, H, Cell); +} + +int GView::ConScroll(int Way, int X, int Y, int W, int H, TAttr Fill, int Count) { + return Peer->ConScroll(Way, X, Y, W, H, Fill, Count); +} + +int GView::ConSetSize(int X, int Y) { + if (Peer->ConSetSize(X, Y)) + Resize(X, Y); + else + return 0; + return 1; +} + +int GView::ConQuerySize(int *X, int *Y) { + return Peer->ConQuerySize(X, Y); +} + +int GView::ConSetCursorPos(int X, int Y) { + return Peer->ConSetCursorPos(X, Y); +} + +int GView::ConQueryCursorPos(int *X, int *Y) { + return Peer->ConQueryCursorPos(X, Y); +} + +int GView::ConShowCursor() { + return Peer->ConShowCursor(); +} + +int GView::ConHideCursor() { + return Peer->ConHideCursor(); +} + +int GView::ConCursorVisible() { + return Peer->ConCursorVisible(); +} + +int GView::ConSetCursorSize(int Start, int End) { + return Peer->ConSetCursorSize(Start, End); +} + +int GView::CaptureMouse(int grab) { + return Peer->CaptureMouse(grab); +} + +int GView::CaptureFocus(int grab) { + return Peer->CaptureFocus(grab); +} + +int GView::QuerySbVPos() { + return Peer->QuerySbVPos(); +} + +int GView::SetSbVPos(int Start, int Amount, int Total) { + return Peer->SetSbVPos(Start, Amount, Total); +} + +int GView::SetSbHPos(int Start, int Amount, int Total) { + return Peer->SetSbHPos(Start, Amount, Total); +} + +int GView::ExpandHeight(int DeltaY) { + return Peer->ExpandHeight(DeltaY); +} + +void GView::Update() { +} + +void GView::Repaint() { +} + +void GView::HandleEvent(TEvent &/*Event*/) { +} + +void GView::Resize(int /*width*/, int /*height*/) { + Repaint(); +} + +void GView::EndExec(int NewResult) { + Result = NewResult; +} + +int GView::Execute() { + int SaveRc = Result; + int NewResult; + int didFocus = 0; + + if (FocusCapture == 0) { + if (CaptureFocus(1) == 0) return -1; + didFocus = 1; + } else + if (FocusCapture != this) + return -1; + Result = -2; + while (Result == -2 && frames != 0) + gui->ProcessEvent(); + NewResult = Result; + Result = SaveRc; + if (didFocus) + CaptureFocus(0); + return NewResult; +} + +int GView::IsActive() { + return (Parent->Active == this); +} + +void GView::Activate(int gotfocus) { + if (gotfocus) { + Peer->wState |= sfFocus; + Peer->UpdateCursor(); + } else { + Peer->wState &= ~sfFocus; + } + Repaint(); +} + +/////////////////////////////////////////////////////////////////////////// + +GFramePeer::GFramePeer(GFrame *aFrame, int Width, int Height) { + Frame = aFrame; + if (Width != -1 && Height != -1) + ConSetSize(Width, Height); + ConQuerySize(&fW, &fH); +} + +GFramePeer::~GFramePeer() { +} + +int GFramePeer::ConSetSize(int X, int Y) { + return ::ConSetSize(X, Y); +} + +int GFramePeer::ConQuerySize(int *X, int *Y) { + ::ConQuerySize(&fW, &fH); + if (X) *X = fW; + if (Y) *Y = fH; + return 1; +} + +//int GFrame::ConQuerySize(int *X, int *Y) { +// ::ConQuerySize(X, Y); +// if (ShowVScroll) +// --*X; +//} + +int GFramePeer::ConSetTitle(char *Title, char *STitle) { + ::ConSetTitle(Title, STitle); + return 0; +} + +int GFramePeer::ConGetTitle(char *Title, int MaxLen, char *STitle, int SMaxLen) { + return ::ConGetTitle(Title, MaxLen, STitle, SMaxLen); +} + +/////////////////////////////////////////////////////////////////////////// + +GFrame::GFrame(int XSize, int YSize) { + Menu = 0; + if (frames == 0) { + frames = Prev = Next = this; + } else { + Next = frames->Next; + Prev = frames; + frames->Next->Prev = this; + frames->Next = this; + frames = this; + } + Top = Active = 0; + Peer = new GFramePeer(this, XSize, YSize); +} + +GFrame::~GFrame() { + if (Peer) { + delete Peer; + Peer = 0; + } + if (Next == this) { + frames = 0; +// printf("No more frames\x7\x7\n"); + } else { + Next->Prev = Prev; + Prev->Next = Next; + frames = Next; + } + Next = Prev = 0; + if (Menu) + free(Menu); +} + +int GFrame::ConSetTitle(char *Title, char *STitle) { + return Peer->ConSetTitle(Title, STitle); +} + +int GFrame::ConGetTitle(char *Title, int MaxLen, char *STitle, int SMaxLen) { + return Peer->ConGetTitle(Title, MaxLen, STitle, SMaxLen); +} + +int GFrame::ConSetSize(int X, int Y) { + return Peer->ConSetSize(X, Y); +} + +int GFrame::ConQuerySize(int *X, int *Y) { + return Peer->ConQuerySize(X, Y); +} + +int GFrame::ConSplitView(GView *view, GView *newview) { + int dmy; + + newview->Parent = this; + newview->Peer->wX = 0; + ConQuerySize(&newview->Peer->wW, &dmy); + if (ShowVScroll) + newview->Peer->wW--; + newview->Peer->wY = view->Peer->wY + view->Peer->wH / 2; + newview->Peer->wH = view->Peer->wH - view->Peer->wH / 2; + if (ShowHScroll) { + newview->Peer->wY++; + newview->Peer->wH--; + } + view->Peer->wH /= 2; + view->ConSetSize(view->Peer->wW, view->Peer->wH); + newview->ConSetSize(newview->Peer->wW, newview->Peer->wH); + InsertView(view, newview); + return 0; +} + +int GFrame::ConCloseView(GView * /*view*/) { + return 0; +} + +int GFrame::ConResizeView(GView * /*view*/, int /*DeltaY*/) { + return 0; +} + +int GFrame::AddView(GView *view) { + if (Active != 0) { + return ConSplitView(Active, view); + } else { + int W, H; + + view->Parent = this; + view->Prev = view->Next = 0; + + view->Peer->wX = 0; + if (ShowMenuBar) + view->Peer->wY = 1; + else + view->Peer->wY = 0; + ConQuerySize(&W, &H); + if (ShowMenuBar) + H--; + if (ShowVScroll) + W--; + if (ShowHScroll) + H--; + view->ConSetSize(W, H); + InsertView(Top, view); + return 0; + } +} + +void GFrame::Update() { + GView *v = Active; + + UpdateMenu(); + while (v) { + v->Update(); + if ((ShowVScroll || ShowHScroll) && (v->Peer->sbVupdate || v->Peer->sbHupdate)) { + v->Peer->DrawScrollBar(); + v->Peer->sbVupdate = 0; + v->Peer->sbHupdate = 0; + } + v = v->Next; + if (v == Active) + break; + } +} + +void GFrame::UpdateMenu() { + if (ShowMenuBar) + DrawMenuBar(); +} + +void GFrame::Repaint() { + GView *v = Active; + + if (ShowMenuBar) + DrawMenuBar(); + while (v) { + v->Repaint(); + if (ShowVScroll || ShowHScroll) { + v->Peer->DrawScrollBar(); + v->Peer->sbVupdate = 0; + v->Peer->sbHupdate = 0; + } + v = v->Next; + if (v == Active) + break; + } +} + +void GFrame::InsertView(GView *Prev, GView *view) { + if (!view) return ; + if (Prev) { + view->Prev = Prev; + view->Next = Prev->Next; + Prev->Next = view; + view->Next->Prev = view; + } else { + view->Prev = view->Next = view; + Top = view; + } + if (Active == 0) { + Active = view; + Active->Activate(1); + } +} + +void GFrame::RemoveView(GView *view) { + if (!view) return ; + + if (Active == view) + Active->Activate(0); + if (view->Next == view) { + Top = Active = 0; + delete this; + } else { + view->Next->Prev = view->Prev; + view->Prev->Next = view->Next; + + if (Top == view) { + Top = view->Next; + Top->Peer->wY -= view->Peer->wH; + Top->ConSetSize(Top->Peer->wW, Top->Peer->wH + view->Peer->wH + (ShowHScroll ? 1 : 0)); + } else { + view->Prev->ConSetSize(view->Prev->Peer->wW, + view->Prev->Peer->wH + view->Peer->wH + (ShowHScroll ? 1 : 0)); + } + + if (Active == view) { + Active = view->Prev; + Active->Activate(1); + } + } +} + +void GFrame::SelectNext(int back) { + GView *c = Active; + + if (c == 0 && Top == 0) + return; + + if (FocusCapture != 0) + return ; + + else if (c == 0) + c = Active = Top; + else + if (back) { + Active = Active->Prev; + } else { + Active = Active->Next; + } + if (c != Active) { + if (c) + c->Activate(0); + if (Active) + Active->Activate(1); + } +} + +int GFrame::SelectView(GView *view) { + if (Top == 0) + return 0; + + if (FocusCapture != 0) + view = view; + + if (Active) + Active->Activate(0); + Active = view; + if (Active) + Active->Activate(1); + return 1; +} + +void GFrame::Resize(int width, int height) { + GView *V; + int count = 0; + + + V = Top; + while (V) { + count++; + if (V == Top) break; + } + if (height < 2 * count + 2 || width < 16) { + ::ConSetSize(16, 2 * count + 1); + return; + } + + if (!Top) + return; + + if (ShowVScroll) + width--; + if (ShowHScroll) + height--; + +// fprintf(stderr, "Resize: %d %d\n", width, height); + + V = Top->Prev; + + while (V != Top) { + int h, y; + + h = V->Peer->wH; + y = V->Peer->wY; + + if (y >= height - 2) { + y = height - 2; + } + if (y + h != height) { + h = height - y; + } + V->Peer->wY = y; + V->ConSetSize(width, h); + height = y; + V = V->Prev; + } + if (ShowMenuBar) + height--; + Top->ConSetSize(width, height); + Repaint(); + // fprintf(stderr, "Resize: %d %d Done\n", width, height); +} + +int GFrame::ExecMainMenu(char Sub) { + NextEvent.What = evCommand; + NextEvent.Msg.Command = cmMainMenu; + NextEvent.Msg.Param1 = Sub; + return 0; +} + +int GFrame::SetMenu(const char *Name) { + if (Menu) free(Menu); + Menu = strdup(Name); + return 0; +} + +void GFrame::Show() { +} + +void GFrame::Activate() { + frames = this; +} + +int GUI::ConGrabEvents(TEventMask /*EventMask*/) { + return 0; +} + +void GUI::DispatchEvent(GFrame * /*frame*/, GView *view, TEvent &Event) { + if (Event.What != evNone) { + if (view) + view->HandleEvent(Event); + } +} + +int GUI::ConGetEvent(TEventMask EventMask, TEvent *Event, int WaitTime, int Delete, GView **view) { + if (view) + *view = 0; + return ::ConGetEvent(EventMask, Event, WaitTime, Delete); +} + +int GUI::ConPutEvent(TEvent Event) { + return ::ConPutEvent(Event); +} + +int GUI::ConFlush(void) { + return 0; +} + +static inline int scrollBreak(TEvent &E) +{ +#if defined(DOS) || defined(DOSP32) + // workaround until mouse code in con_dosx.cpp is finished + return (E.What != evMouseDown); +#else + return (E.What == evMouseUp); +#endif +} + +void HandleVScroll(GView *view, TEvent &E) { + int y; //, x + int wY, wH; + TEvent E1; + + //x = E.Mouse.X; + y = E.Mouse.Y; + wY = view->Peer->wY; + wH = view->Peer->wH; + if (y == wY) { + do { + E1.What = evCommand; + E1.Msg.View = view; + E1.Msg.Command = cmVScrollUp; + gui->DispatchEvent(frames, view, E1); + frames->Update(); + do { + ConGetEvent(evMouse | evNotify, &E, -1, 1); + if (E.What & evNotify) + gui->DispatchEvent(frames, view, E); + } while (E.What & evNotify); + if (scrollBreak(E)) break; + } while (1); + } else if (y == wY + wH - 1) { + do { + E1.What = evCommand; + E1.Msg.View = view; + E1.Msg.Command = cmVScrollDown; + gui->DispatchEvent(frames, view, E1); + frames->Update(); + do { + ConGetEvent(evMouse | evNotify, &E, -1, 1); + if (E.What & evNotify) + gui->DispatchEvent(frames, view, E); + } while (E.What & evNotify); + if (scrollBreak(E)) break; + } while (1); + } else if (y < wY + view->Peer->SbVBegin + 1) { + do { + E1.What = evCommand; + E1.Msg.View = view; + E1.Msg.Command = cmVScrollPgUp; + gui->DispatchEvent(frames, view, E1); + frames->Update(); + do { + ConGetEvent(evMouse | evNotify, &E, -1, 1); + if (E.What & evNotify) + gui->DispatchEvent(frames, view, E); + } while (E.What & evNotify); + if (scrollBreak(E)) break; + } while (1); + } else if (y > wY + view->Peer->SbVEnd + 1) { + do { + E1.What = evCommand; + E1.Msg.View = view; + E1.Msg.Command = cmVScrollPgDn; + gui->DispatchEvent(frames, view, E1); + frames->Update(); + do { + ConGetEvent(evMouse | evNotify, &E, -1, 1); + if (E.What & evNotify) + gui->DispatchEvent(frames, view, E); + } while (E.What & evNotify); + if (scrollBreak(E)) break; + } while (1); + } else { + int delta = y - 1 - view->Peer->SbVBegin - wY; + + do { + E1.What = evCommand; + E1.Msg.View = view; + E1.Msg.Command = cmVScrollMove; + E1.Msg.Param1 = (E.Mouse.Y - wY - 1 - delta + 1) * view->Peer->sbVtotal / (wH - 2); +// printf("YPos = %d %d %d \n\x7", E.Mouse.Y, wY, delta); + gui->DispatchEvent(frames, view, E1); + frames->Update(); + do { + ConGetEvent(evMouse | evNotify, &E, -1, 1); + if (E.What & evNotify) + gui->DispatchEvent(frames, view, E); + } while (E.What & evNotify); + if (scrollBreak(E)) break; + } while (1); + } + E.What = evNone; +} + +void HandleHScroll(GView *view, TEvent &E) { + int x; //, x + int wX, wW; + TEvent E1; + + //x = E.Mouse.X; + x = E.Mouse.X; + wX = view->Peer->wX; + wW = view->Peer->wW; + if (x == wX) { + do { + E1.What = evCommand; + E1.Msg.View = view; + E1.Msg.Command = cmHScrollLeft; + gui->DispatchEvent(frames, view, E1); + frames->Update(); + do { + ConGetEvent(evMouse | evNotify, &E, -1, 1); + if (E.What & evNotify) + gui->DispatchEvent(frames, view, E); + } while (E.What & evNotify); + if (scrollBreak(E)) break; + } while (1); + } else if (x == wX + wW - 1) { + do { + E1.What = evCommand; + E1.Msg.View = view; + E1.Msg.Command = cmHScrollRight; + gui->DispatchEvent(frames, view, E1); + frames->Update(); + do { + ConGetEvent(evMouse | evNotify, &E, -1, 1); + if (E.What & evNotify) + gui->DispatchEvent(frames, view, E); + } while (E.What & evNotify); + if (scrollBreak(E)) break; + } while (1); + } else if (x < wX + view->Peer->SbHBegin + 1) { + do { + E1.What = evCommand; + E1.Msg.View = view; + E1.Msg.Command = cmHScrollPgLt; + gui->DispatchEvent(frames, view, E1); + frames->Update(); + do { + ConGetEvent(evMouse | evNotify, &E, -1, 1); + if (E.What & evNotify) + gui->DispatchEvent(frames, view, E); + } while (E.What & evNotify); + if (scrollBreak(E)) break; + } while (1); + } else if (x > wX + view->Peer->SbHEnd + 1) { + do { + E1.What = evCommand; + E1.Msg.View = view; + E1.Msg.Command = cmHScrollPgRt; + gui->DispatchEvent(frames, view, E1); + frames->Update(); + do { + ConGetEvent(evMouse | evNotify, &E, -1, 1); + if (E.What & evNotify) + gui->DispatchEvent(frames, view, E); + } while (E.What & evNotify); + if (scrollBreak(E)) break; + } while (1); + } else { + int delta = x - 1 - view->Peer->SbHBegin - wX; + + do { + E1.What = evCommand; + E1.Msg.View = view; + E1.Msg.Command = cmHScrollMove; + E1.Msg.Param1 = (E.Mouse.X - wX - 1 - delta + 1) * view->Peer->sbHtotal / (wW - 2); +// printf("YPos = %d %d %d \n\x7", E.Mouse.Y, wY, delta); + gui->DispatchEvent(frames, view, E1); + frames->Update(); + do { + ConGetEvent(evMouse | evNotify, &E, -1, 1); + if (E.What & evNotify) + gui->DispatchEvent(frames, view, E); + } while (E.What & evNotify); + if (scrollBreak(E)) break; + } while (1); + } + E.What = evNone; +} + +void GUI::ProcessEvent() { + TEvent E; + + E = NextEvent; + if (E.What != evNone) { + NextEvent.What = evNone; + } + if (E.What == evNone && + ( ConGetEvent(evMouse | evCommand | evKeyboard, &E, 0, 1, 0) == -1 || + E.What == evNone ) + ) + { + frames->Update(); + while(ConGetEvent(evMouse | evCommand | evKeyboard, &E, -1, 1, 0) == -1 || + (E.What == evMouseMove && E.Mouse.Buttons == 0)); + } + if (E.What != evNone) { + GView *view = frames->Active; + + if (E.What & evMouse) { + if (E.What == evMouseDown && E.Mouse.Y == 0 && ShowMenuBar && + MouseCapture == 0 && FocusCapture == 0) + { + frames->Update(); // sync before menu + if (ExecMainMenu(E, 0) == -1) { + if (E.What == evCommand && E.Msg.Command == cmResize) { + int X, Y; + + ConQuerySize(&X, &Y); + frames->Resize(X, Y); + } + E.What = evNone; + } +// fprintf(stderr, "Command got = %d\n", E.Msg.Command); + } + if (E.What == evMouseDown && MouseCapture == 0 && FocusCapture == 0) { + GView *V = frames->Active; + + while (V) { + if (E.Mouse.Y >= V->Peer->wY && + E.Mouse.Y < V->Peer->wY + V->Peer->wH + (ShowHScroll ? 1 : 0)) + { + frames->SelectView(V); + view = V; + break; + } + V = V->Next; + if (V == frames->Active) + break; + } + } + if (ShowVScroll && ShowHScroll && E.What == evMouseDown && + MouseCapture == 0 && FocusCapture == 0 && + E.Mouse.Y == view->Peer->wY + view->Peer->wH && + E.Mouse.X == view->Peer->wX + view->Peer->wW) + { + } else { + if (ShowVScroll && E.What == evMouseDown && MouseCapture == 0 && FocusCapture == 0 && + E.Mouse.X == view->Peer->wX + view->Peer->wW) + { + HandleVScroll(view, E); + return ; + } + if (ShowHScroll && E.What == evMouseDown && MouseCapture == 0 && FocusCapture == 0 && + E.Mouse.Y == view->Peer->wY + view->Peer->wH) + { + HandleHScroll(view, E); + return ; + } + } + if (E.What & evMouse) { + E.Mouse.Y -= view->Peer->wY; + E.Mouse.X -= view->Peer->wX; + } + } + if (E.What == evCommand) { + switch (E.Msg.Command) { + case cmResize: + { + int X, Y; + + ConQuerySize(&X, &Y); + frames->Resize(X, Y); + } + break; + case cmMainMenu: + { + char Sub = (char)E.Msg.Param1; + + frames->Update(); // sync before menu + if (::ExecMainMenu(E, Sub) != 1) {; + if (E.What == evCommand && E.Msg.Command == cmResize) { + int X, Y; + + ConQuerySize(&X, &Y); + frames->Resize(X, Y); + } + E.What = evNone; + } + } + break; + case cmPopupMenu: + { + int id = E.Msg.Param1; + int Cols, Rows; + + if (id == -1) return; + frames->ConQuerySize(&Cols, &Rows); + int x = Cols / 2, y = Rows / 2; + ::ConQueryMousePos(&x, &y); + + frames->Update(); // sync before menu + if (::ExecVertMenu(x, y, id, E, 0) != 1) { + if (E.What == evCommand && E.Msg.Command == cmResize) { + int X, Y; + + ConQuerySize(&X, &Y); + frames->Resize(X, Y); + } + E.What = evNone; + } + } + break; + } + } + if (E.What != evNone) + DispatchEvent(frames, view, E); + } +} + +int GUI::Run() { + if (Start(fArgc, fArgv) == 0) { + doLoop = 1; + while (doLoop) + ProcessEvent(); + Stop(); + return 0; + } + return 1; +} + +int GUI::multiFrame() { + return 0; +} + +void DieError(int rc, const char *msg, ...) { + va_list ap; + + va_start(ap, msg); + vfprintf(stderr, msg, ap); + va_end(ap); + fprintf(stderr, "\n"); + exit(rc); +} diff --git a/src/gui.cpp b/src/gui.cpp new file mode 100644 index 0000000..3a30963 --- /dev/null +++ b/src/gui.cpp @@ -0,0 +1,41 @@ +#include +#include +#include +#include +#include + +#include "console.h" +#include "gui.h" + +int GFrame::isLastFrame() { + if (this == Next && frames == this) + return 1; + else + return 0; +} + +void GUI::deleteFrame(GFrame *frame) { + if (frame->isLastFrame()) { + delete frame; + frames = 0; + } else { + //frame->Prev->Next = frame->Next; + //frame->Next->Prev = frame->Prev; + //if (frames == frame) + // frames = frame->Next; + + //frames->Activate(); + delete frame; + } +} + +int GUI::Start(int &/*argc*/, char ** /*argv*/) { + return 0; +} + +void GUI::Stop() { +} + +void GUI::StopLoop() { + doLoop = 0; +} diff --git a/src/gui.h b/src/gui.h new file mode 100644 index 0000000..014baab --- /dev/null +++ b/src/gui.h @@ -0,0 +1,214 @@ +/* gui.h + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#ifndef __GUI_H +#define __GUI_H + +#define RUN_WAIT 0 +#define RUN_ASYNC 1 + +class GFramePeer; +class GViewPeer; + +class GUI; +class GFrame; + +class GView { +public: + GFrame *Parent; + GView *Next, *Prev; + GViewPeer *Peer; + int Result; + + GView(GFrame *parent, int XSize, int YSize); + virtual ~GView(); + + int ConClear(); + int ConPutBox(int X, int Y, int W, int H, PCell Cell); + int ConGetBox(int X, int Y, int W, int H, PCell Cell); + int ConPutLine(int X, int Y, int W, int H, PCell Cell); + int ConSetBox(int X, int Y, int W, int H, TCell Cell); + int ConScroll(int Way, int X, int Y, int W, int H, TAttr Fill, int Count); + + int ConSetSize(int X, int Y); + int ConQuerySize(int *X, int *Y); + + int ConSetCursorPos(int X, int Y); + int ConQueryCursorPos(int *X, int *Y); + int ConShowCursor(); + int ConHideCursor(); + int ConCursorVisible(); + int ConSetCursorSize(int Start, int End); + + int CaptureMouse(int grab); + int CaptureFocus(int grab); + + virtual int Execute(); + void EndExec(int NewResult); + + int QuerySbVPos(); + int SetSbVPos(int Start, int Amount, int Total); + int SetSbHPos(int Start, int Amount, int Total); + int ExpandHeight(int DeltaY); + + int IsActive(); + + virtual void Update(); + virtual void Repaint(); + virtual void Activate(int gotfocus); + virtual void Resize(int width, int height); + virtual void HandleEvent(TEvent &Event); +}; + +class GFrame { +public: + GFrame *Prev, *Next; + GView *Top, *Active; + GFramePeer *Peer; + char *Menu; + + GFrame(int XSize, int YSize); + virtual ~GFrame(); + + int ConSetTitle(char *Title, char *STitle); + int ConGetTitle(char *Title, int MaxLen, char *STitle, int SMaxLen); + + int ConSetSize(int X, int Y); + int ConQuerySize(int *X, int *Y); + + int AddView(GView *view); + int ConSplitView(GView *view, GView *newview); + int ConCloseView(GView *view); + int ConResizeView(GView *view, int DeltaY); + int SelectView(GView *view); + + virtual void Update(); + virtual void Repaint(); + virtual void UpdateMenu(); + + void InsertView(GView *Prev, GView *view); + void RemoveView(GView *view); + void SelectNext(int back); + + void Resize(int width, int height); + void DrawMenuBar(); + + int ExecMainMenu(char Sub); + int SetMenu(const char *Name); + char *QueryMenu(); + int PopupMenu(const char *Name); + + void Show(); + void Activate(); + + int isLastFrame(); +}; + +class GUI { +public: + GUI(int &argc, char **argv, int XSize, int YSize); + virtual ~GUI(); + + int ConSuspend(); + int ConContinue(); + int ShowEntryScreen(); + + void ProcessEvent(); + virtual void DispatchEvent(GFrame *frame, GView *view, TEvent &Event); + int ConGetEvent(TEventMask EventMask, TEvent *Event, int WaitTime, int Delete, GView **view); + int ConPutEvent(TEvent Event); + int ConFlush(void); + int ConGrabEvents(TEventMask EventMask); + + virtual int Start(int &argc, char **argv); + virtual void Stop(); + + int Run(); + void StopLoop(); + + int RunProgram(int mode, char *Command); + + int OpenPipe(char *Command, EModel *notify); + int SetPipeView(int id, EModel *notify); + int ReadPipe(int id, void *buffer, int len); + int ClosePipe(int id); + + int multiFrame(); + void deleteFrame(GFrame *frame); + + int fArgc; + char **fArgv; + int doLoop; +}; + +extern GFrame *frames; +extern GUI *gui; + +#define GUIDLG_CHOICE 0x00000001 +#define GUIDLG_PROMPT 0x00000002 +#define GUIDLG_PROMPT2 0x00000004 +#define GUIDLG_FILE 0x00000008 +#define GUIDLG_FIND 0x00000010 +#define GUIDLG_FINDREPLACE 0x00000020 + +extern unsigned long HaveGUIDialogs; + +void DieError(int rc, const char *msg, ...); + +#define GF_OPEN 0x0001 +#define GF_SAVEAS 0x0002 + +int DLGGetStr(GView *View, const char *Prompt, unsigned int BufLen, char *Str, int HistId, int Flags); +int DLGGetFile(GView *View, const char *Prompt, unsigned int BufLen, char *FileName, int Flags); + +#define GPC_NOTE 0x0000 +#define GPC_CONFIRM 0x0001 +#define GPC_WARNING 0x0002 +#define GPC_ERROR 0x0004 +#define GPC_FATAL 0x0008 +int DLGPickChoice(GView *View, const char *ATitle, int NSel, va_list ap, int Flags); + +#define SEARCH_BACK 0x00000001 // reverse (TODO for regexps) +#define SEARCH_RE 0x00000002 // use regexp +#define SEARCH_NCASE 0x00000004 // case +#define SEARCH_GLOBAL 0x00000008 // start from beggining (or end if BACK) +#define SEARCH_BLOCK 0x00000010 // search in block +#define SEARCH_NEXT 0x00000020 // next match +#define SEARCH_NASK 0x00000040 // ask before replacing +#define SEARCH_ALL 0x00000080 // search all +#define SEARCH_REPLACE 0x00000100 // do a replace operation +#define SEARCH_JOIN 0x00000200 // join line +#define SEARCH_DELETE 0x00000400 // delete line +#define SEARCH_CENTER 0x00001000 // center finds +#define SEARCH_NOPOS 0x00002000 // don't move the cursor +#define SEARCH_WORDBEG 0x00004000 // match at beginning of words only +#define SEARCH_WORDEND 0x00008000 // match at end of words only +#define SEARCH_WORD (SEARCH_WORDBEG | SEARCH_WORDEND) +//0x00000800 // search words +//#define SEARCH_LINE 0x00002000 // search on current line only TODO +//#define SEARCH_WRAP 0x00004000 // similiar to GLOBAL, but goes to start +// only when match from current position fails TODO +//#define SEARCH_BOL 0x00008000 // search at line start +//#define SEARCH_EOL 0x00010000 // search at line end + +#define MAXSEARCH 512 + +typedef struct { + int ok; + char strSearch[MAXSEARCH]; + char strReplace[MAXSEARCH]; + unsigned long Options; + // + int resCount; +} SearchReplaceOptions; + +int DLGGetFind(GView *View, SearchReplaceOptions &sr); +int DLGGetFindReplace(GView *View, SearchReplaceOptions &sr); + +#endif diff --git a/src/h_ada.cpp b/src/h_ada.cpp new file mode 100644 index 0000000..3b894ab --- /dev/null +++ b/src/h_ada.cpp @@ -0,0 +1,130 @@ +/* h_ada.cpp + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#include "fte.h" + +#ifdef CONFIG_HILIT_ADA + +#define hsAda_Normal 0 +#define hsAda_Comment 1 +#define hsAda_CommentL 2 +#define hsAda_Keyword 4 +#define hsAda_String1 10 +#define hsAda_String2 11 + +int Hilit_ADA(EBuffer *BF, int /*LN*/, PCell B, int Pos, int Width, ELine *Line, hlState &State, hsState *StateMap, int *ECol) { + ChColor *Colors = BF->Mode->fColorize->Colors; + int j = 0; + int firstnw = 0; + HILIT_VARS(Colors[CLR_Normal], Line); + int len1 = len; +// char *last = p + len1 - 1; + + C = 0; + NC = 0; + for(i = 0; i < Line->Count;) { + if (*p != ' ' && *p != 9) firstnw++; + IF_TAB() else { + switch (State) { + default: + case hsAda_Normal: + if (isalpha(*p) || *p == '_') { + j = 0; + while (((i + j) < Line->Count) && + (isalnum(Line->Chars[i+j]) || + (Line->Chars[i + j] == '_') || + (Line->Chars[i + j] == '\'')) + ) j++; + if (BF->GetHilitWord(j, &Line->Chars[i], Color, 1)) { + State = hsAda_Keyword; + } else { + int x; + x = i + j; + while ((x < Line->Count) && + ((Line->Chars[x] == ' ') || (Line->Chars[x] == 9))) x++; + if ((x < Line->Count) && (Line->Chars[x] == '(')) { + Color = Colors[CLR_Function]; + } else { + Color = Colors[CLR_Normal]; + } + State = hsAda_Normal; + } + if (StateMap) + memset(StateMap + i, State, j); + if (B) + MoveMem(B, C - Pos, Width, Line->Chars + i, Color, j); + i += j; + len -= j; + p += j; + C += j; + State = hsAda_Normal; + continue; + } else if ((len >= 2) && (*p == '-') && (*(p+1) == '-')) { + State = hsAda_CommentL; + Color = Colors[CLR_Comment]; + //hilit2: + ColorNext(); + hilit: + ColorNext(); + continue; + } else if (isdigit(*p)) { + Color = Colors[CLR_Number]; + ColorNext(); + while (len && (isdigit(*p) || *p == 'e' || *p == 'E' || *p == '.' || *p == '_')) ColorNext(); + continue; + } else if (*p == '\'') { + State = hsAda_String1; + Color = Colors[CLR_String]; + goto hilit; + } else if (*p == '"') { + State = hsAda_String2; + Color = Colors[CLR_String]; + goto hilit; + } else if (ispunct(*p) && *p != '_') { + Color = Colors[CLR_Punctuation]; + goto hilit; + } + Color = Colors[CLR_Normal]; + goto hilit; + case hsAda_CommentL: + Color = Colors[CLR_Comment]; + goto hilit; + case hsAda_String1: + Color = Colors[CLR_String]; + if (*p == '\'') { + ColorNext(); + State = hsAda_Normal; + continue; + } + goto hilit; + case hsAda_String2: + Color = Colors[CLR_String]; + if (*p == '"') { + ColorNext(); + State = hsAda_Normal; + continue; + } + goto hilit; + } + } + } + if (State == hsAda_CommentL) + State = hsAda_Normal; + if ((len1 == 0)) { + switch (State) { + case hsAda_String1: + case hsAda_String2: + State = hsAda_Normal; + break; + } + } + *ECol = C; + return 0; +} +#endif diff --git a/src/h_c.cpp b/src/h_c.cpp new file mode 100644 index 0000000..ab96372 --- /dev/null +++ b/src/h_c.cpp @@ -0,0 +1,1340 @@ +/* h_c.cpp + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#define NEED_LOG_H +#include "fte.h" + +#ifdef CONFIG_HILIT_C + + +#define PRINTF(x) //printf x + +#define ISNAME(x) (isalnum(x) || (x == '_')) + + +#define hsC_Normal 0 +#define hsC_Comment 1 +#define hsC_CommentL 2 +#define hsC_Keyword 4 +#define hsC_String1 10 +#define hsC_String2 11 +#define hsC_CPP 12 +#define hsC_CPP_Comm 13 +#define hsC_CPP_String1 14 +#define hsC_CPP_String2 15 +#define hsC_CPP_ABrace 16 + +int Hilit_C(EBuffer *BF, int /*LN*/, PCell B, int Pos, int Width, ELine *Line, hlState &State, hsState *StateMap, int *ECol) { + ChColor *Colors = BF->Mode->fColorize->Colors; + int j = 0; + int firstnw = 0; + HILIT_VARS(Colors[CLR_Normal], Line); + int len1 = len; + char *last = p + len1 - 1; + int was_include = 0; + + for(i = 0; i < Line->Count;) { + if (*p != ' ' && *p != 9) firstnw++; + IF_TAB() else { + switch(State) { + default: + case hsC_Normal: + if (toupper(*p) == 'L' && p[1] == '"') { + State = hsC_String2; + Color = Colors[CLR_String]; + goto hilit2; + } else if (toupper(*p) == 'L' && p[1] == '\'') { + State = hsC_String1; + Color = Colors[CLR_String]; + goto hilit2; + } else if (isalpha(*p) || *p == '_') { + j = 0; + while (((i + j) < Line->Count) + && ISNAME(Line->Chars[i + j])) + j++; + if (BF->GetHilitWord(j, &Line->Chars[i], Color)) { + // Color = hcC_Keyword; + State = hsC_Keyword; + } else { + int x; + x = i + j; + while (x < Line->Count && isspace(Line->Chars[x])) + x++; + if (x < Line->Count && Line->Chars[x] == '(') { + Color = Colors[CLR_Function]; + } else if ((x < Line->Count) + && (Line->Chars[x] == ':' + && (x == Line->Count - 1 + || Line->Chars[x + 1] != ':')) + && firstnw == 1) { + Color = Colors[CLR_Label]; + } else { + Color = Colors[CLR_Normal]; + } + State = hsC_Normal; + } + if (StateMap) + memset(StateMap + i, State, j); + if (B) + MoveMem(B, C - Pos, Width, Line->Chars + i, Color, j); + i += j; + len -= j; + p += j; + C += j; + State = hsC_Normal; + continue; + } else if ((len >= 2) && (*p == '/') && (*(p+1) == '*')) { + State = hsC_Comment; + Color = Colors[CLR_Comment]; + goto hilit2; + } else if ((len >= 2) && (*p == '/') && (p[1] == '/')) { + State = hsC_CommentL; + Color = Colors[CLR_Comment]; + goto hilit2; + } else if (isdigit(*p)) { + // check if it is not floating point number 0.08! + if ((len >= 2) && (*p == '0') && p[1] != '.') { + if (toupper(*(p+1)) == 'X') { + Color = Colors[CLR_HexNumber]; + ColorNext(); + ColorNext(); + while (len && isxdigit(*p)) ColorNext(); + } else /* assume it's octal */ { + Color = Colors[CLR_Number]; + ColorNext(); + while (len && ('0' <= *p && *p <= '7')) ColorNext(); + // if we hit a non-octal, stop hilighting it. + if (len && ('8' <= *p && *p <= '9')) + { + Color = Colors[CLR_Normal]; + while (len && !isspace(*p)) ColorNext(); + continue; + } + } + } else /* assume it's decimal/floating */ { + Color = Colors[CLR_Number]; + ColorNext(); + while (len && (isdigit(*p) || *p == 'e' || *p == 'E' || *p == '.')) ColorNext(); + // if it ends with 'f', the number can't have more extras. + if (len && (toupper(*p) == 'F')) { + ColorNext(); + continue; + } + } + // allowed extras: u, l, ll, ul, ull, lu, llu + int colored_u = 0; + if (len && (toupper(*p) == 'U')) { + ColorNext(); + colored_u = 1; + } + if (len && (toupper(*p) == 'L')) { + ColorNext(); + if (len && (toupper(*p) == 'L')) ColorNext(); + if (! colored_u && len && (toupper(*p) == 'U')) ColorNext(); + } + continue; + } else if (*p == '\'') { + State = hsC_String1; + Color = Colors[CLR_String]; + goto hilit; + } else if (*p == '"') { + State = hsC_String2; + Color = Colors[CLR_String]; + goto hilit; + } else if (firstnw == 1 && *p == '#') { + State = hsC_CPP; + Color = Colors[CLR_CPreprocessor]; + goto hilit; + } else if (ispunct(*p) && *p != '_') { + Color = Colors[CLR_Punctuation]; + goto hilit; + } + Color = Colors[CLR_Normal]; + goto hilit; + case hsC_Comment: + Color = Colors[CLR_Comment]; + if ((len >= 2) && (*p == '*') && (*(p+1) == '/')) { + ColorNext(); + ColorNext(); + State = hsC_Normal; + continue; + } + goto hilit; + case hsC_CPP_Comm: + Color = Colors[CLR_Comment]; + if ((len >= 2) && (*p == '*') && (*(p+1) == '/')) { + ColorNext(); + ColorNext(); + State = hsC_CPP; + continue; + } + goto hilit; + case hsC_CPP_ABrace: + Color = Colors[CLR_String]; + if (*p == '>') { + Color = Colors[CLR_CPreprocessor]; + State = hsC_CPP; + } + goto hilit; + case hsC_CommentL: + Color = Colors[CLR_Comment]; + goto hilit; + case hsC_String1: + Color = Colors[CLR_String]; + if ((len >= 2) && (*p == '\\')) { + goto hilit2; + } else if (*p == '\'') { + ColorNext(); + State = hsC_Normal; + continue; + } + goto hilit; + case hsC_String2: + Color = Colors[CLR_String]; + if ((len >= 2) && (*p == '\\')) { + goto hilit2; + } else if (*p == '"') { + ColorNext(); + State = hsC_Normal; + continue; + } + goto hilit; + case hsC_CPP_String1: + Color = Colors[CLR_String]; + if ((len >= 2) && (*p == '\\')) { + goto hilit2; + } else if (*p == '\'') { + ColorNext(); + State = hsC_CPP; + continue; + } + goto hilit; + case hsC_CPP_String2: + Color = Colors[CLR_String]; + if ((len >= 2) && (*p == '\\')) { + goto hilit2; + } else if (*p == '"') { + ColorNext(); + State = hsC_CPP; + continue; + } + goto hilit; + case hsC_CPP: + if (ISNAME(*p)) { + j = 0; + Color = Colors[CLR_CPreprocessor]; + while (((i + j) < Line->Count) && + (isalnum(Line->Chars[i+j]) || + (Line->Chars[i + j] == '_')) + ) j++; + if (j == 7 && memcmp(Line->Chars + i, "include", 7) == 0) + was_include = 1; + if (StateMap) + memset(StateMap + i, State, j); + if (B) + MoveMem(B, C - Pos, Width, Line->Chars + i, Color, j); + i += j; + len -= j; + p += j; + C += j; + continue; + } else if ((len >= 2) && (*p == '/') && (*(p+1) == '*')) { + State = hsC_CPP_Comm; + Color = Colors[CLR_Comment]; + goto hilit2; + } else if ((len >= 2) && (*p == '/') && (*(p+1) == '/')) { + State = hsC_CommentL; + Color = Colors[CLR_Comment]; + hilit2: + ColorNext(); + hilit: + ColorNext(); + continue; + } else if (isdigit(*p)) { + if ((len >= 2) && (*p == '0')) { + if (toupper(*(p+1)) == 'X') { + Color = Colors[CLR_HexNumber]; + ColorNext(); + ColorNext(); + while (len && isxdigit(*p)) ColorNext(); + } else /* assume it's octal */ { + Color = Colors[CLR_Number]; + ColorNext(); + while (len && ('0' <= *p && *p <= '7')) ColorNext(); + // if we hit a non-octal, stop hilighting it. + if (len && ('8' <= *p && *p <= '9')) + { + Color = Colors[CLR_Normal]; + while (len && !isspace(*p)) ColorNext(); + continue; + } + } + } else /* assume it's decimal/floating */ { + Color = Colors[CLR_Number]; + ColorNext(); + while (len && (isdigit(*p) || *p == 'e' || *p == 'E' || *p == '.')) ColorNext(); + // if it ends with 'f', the number can't have more extras. + if (len && (toupper(*p) == 'F')) { + ColorNext(); + continue; + } + } + // allowed extras: u, l, ll, ul, ull, lu, llu + int colored_u = 0; + if (len && (toupper(*p) == 'U')) { + ColorNext(); + colored_u = 1; + } + if (len && (toupper(*p) == 'L')) { + ColorNext(); + if (len && (toupper(*p) == 'L')) ColorNext(); + if (! colored_u && len && (toupper(*p) == 'U')) ColorNext(); + } + continue; + } else if (*p == '\'') { + State = hsC_CPP_String1; + Color = Colors[CLR_String]; + goto hilit; + } else if (*p == '"') { + State = hsC_CPP_String2; + Color = Colors[CLR_String]; + goto hilit; + } else if (*p == '<' && was_include) { + ColorNext(); + State = hsC_CPP_ABrace; + continue; + } else { + Color = Colors[CLR_CPreprocessor]; + goto hilit; + } + } + } + } + if (State == hsC_CommentL) + State = hsC_Normal; + if ((len1 == 0) || (*last != '\\')) { + switch(State) { + case hsC_String1: + case hsC_String2: + case hsC_CPP: + case hsC_CPP_String1: + case hsC_CPP_String2: + State = hsC_Normal; + break; + } + } + *ECol = C; + return 0; +} + +int IsState(hsState *Buf, hsState State, int Len) { + int I; + + for(I = 0; I < Len; I++) + if (Buf[I] != State) return 0; + return 1; +} + +int LookAt(EBuffer *B, int Row, unsigned int Pos, const char *What, hsState State, int NoWord, int CaseInsensitive) { + STARTFUNC("LookAt{h_c.cpp}"); + + int Len = strlen(What); + + if (Row < 0 || Row >= B->RCount) { + LOG << "Row out of range: " << Row << " vs " << B->RCount << ENDLINE; + ENDFUNCRC(0); + } + char* pLine = B->RLine(Row)->Chars; + unsigned int uLineLength = B->RLine(Row)->Count; + Pos = B->CharOffset(B->RLine(Row), Pos); + if (Pos + strlen(What) > uLineLength) { ENDFUNCRC(0); } + if (NoWord && uLineLength > Pos + Len && ISNAME(pLine[Pos + Len])) + { + ENDFUNCRC(0); + } + LOG << "Check against [" << What << ']' << ENDLINE; + if ( + (CaseInsensitive && memicmp(pLine + Pos, (char *)What, Len) == 0) || + (!CaseInsensitive && memcmp(pLine + Pos, (char *)What, Len) == 0) + ) + { + ENDFUNCRC(1); + } + else + { + ENDFUNCRC(0); + } +} + +#ifdef CONFIG_INDENT_C + +int C_Indent = 4; +int C_BraceOfs = 0; +int C_ParenDelta = -1; +int C_CaseOfs = 0; +int C_CaseDelta = 4; +int C_ClassOfs = 0; +int C_ClassDelta = 4; +int C_ColonOfs = 0;//-4; +int C_CommentOfs = 0; +int C_CommentDelta = 1; +int C_FirstLevelWidth = -1; +int C_FirstLevelIndent = 4; +int C_Continuation = 4; + +// this is global, unfortunately -- FIX !!! +int EBuffer::SetCIndentStyle(ExState &State) { + if (State.GetIntParam(View, &C_Indent) == 0) + return 0; + if (State.GetIntParam(View, &C_BraceOfs) == 0) + return 0; + if (State.GetIntParam(View, &C_ParenDelta) == 0) + return 0; + if (State.GetIntParam(View, &C_CaseOfs) == 0) + return 0; + if (State.GetIntParam(View, &C_CaseDelta) == 0) + return 0; + if (State.GetIntParam(View, &C_ClassOfs) == 0) + return 0; + if (State.GetIntParam(View, &C_ClassDelta) == 0) + return 0; + if (State.GetIntParam(View, &C_ColonOfs) == 0) + return 0; + if (State.GetIntParam(View, &C_CommentOfs) == 0) + return 0; + if (State.GetIntParam(View, &C_CommentDelta) == 0) + return 0; + if (State.GetIntParam(View, &C_FirstLevelWidth) == 0) + return 0; + if (State.GetIntParam(View, &C_FirstLevelIndent) == 0) + return 0; + if (State.GetIntParam(View, &C_Continuation) == 0) + return 0; + return 1; +} + +#define C_INDENT C_Indent +#define C_BRACE_OFS C_BraceOfs +#define C_PAREN_DELTA C_ParenDelta +#define C_CASE_OFS C_CaseOfs +#define C_CASE_DELTA C_CaseDelta +#define C_CLASS_OFS C_ClassOfs +#define C_CLASS_DELTA C_ClassDelta +#define C_COLON_OFS C_ColonOfs +#define C_COMMENT_OFS C_CommentOfs +#define C_COMMENT_DELTA C_CommentDelta +#define C_CONTINUATION C_Continuation +#define C_FIRST_INDENT C_FirstLevelIndent +#define C_FIRST_WIDTH C_FirstLevelWidth + +#define FIND_IF 0x0001 +#define FIND_SEMICOLON 0x0002 +#define FIND_COMMA 0x0004 +#define FIND_COLON 0x0008 +#define FIND_ELSE 0x0010 +#define FIND_FOR 0x0020 +#define FIND_WHILE 0x0040 +#define FIND_ENDBLOCK 0x0080 +//#define FIND_BEGINBLOCK 0x0100 +#define FIND_CLASS 0x0200 +#define FIND_CASE 0x0400 +#define FIND_SWITCH 0x0800 +#define FIND_QUESTION 0x1000 + +static int CheckLabel(EBuffer *B, int Line) { + PELine L = B->RLine(Line); + int P = B->CharOffset(L, B->LineIndented(Line)); + int Cnt = 0; + + if (Line > 0 && B->RLine(Line - 1)->StateE != hsC_Normal) + return 0; + + while ((P < L->Count) && + (L->Chars[P] == ' ' || L->Chars[P] == 9)) P++; + while (P < L->Count) { + if (Cnt > 0) + if (L->Chars[P] == ':' && (Cnt == 1 || L->Chars[P + 1] != ':')) return 1; + if (!isalnum(L->Chars[P]) && L->Chars[P] != '_') return 0; + Cnt++; + P++; + } + return 0; +} + +static int SearchBackMatch(int Count, EBuffer *B, int Row, hsState State, const char *Open, const char *Close, int *OPos, int *OLine, int matchparens = 0, int bolOnly = 0) { + char *P; + int L; + int Pos; + int LOpen = strlen(Open); + int LClose = strlen(Close); + int StateLen; + hsState *StateMap; + int CountX[3] = { 0, 0, 0 }; + int didMatch = 0; + + *OLine = Row; + *OPos = 0; + while (Row >= 0) { + P = B->RLine(Row)->Chars; + L = B->RLine(Row)->Count; + StateMap = NULL; + if (B->GetMap(Row, &StateLen, &StateMap) == 0) return -1; + Pos = L - 1; + if (L > 0) while (Pos >= 0) { + if (P[Pos] != ' ' && P[Pos] != 9) { + if (StateMap[Pos] == hsC_Normal) { + switch (P[Pos]) { + case '{': CountX[0]--; break; + case '}': CountX[0]++; break; + case '(': CountX[1]--; break; + case ')': CountX[1]++; break; + case '[': CountX[2]--; break; + case ']': CountX[2]++; break; + } + } + if (!matchparens || + (CountX[0] == 0 && CountX[1] == 0 && CountX[2] == 0)) + { + if (LOpen + Pos <= L) { + if (IsState(StateMap + Pos, State, LOpen)) { + if (memcmp(P + Pos, Open, LOpen) == 0) Count++; + if (Count == 0) { + if (bolOnly) + didMatch = 1; + else { + *OPos = B->ScreenPos(B->RLine(Row), Pos); + *OLine = Row; + free(StateMap); + return B->LineIndented(Row); + } + } + } + if (LClose + Pos <= L) { + if (IsState(StateMap + Pos, State, LClose)) { + if (memcmp(P + Pos, Close, LClose) == 0) Count--; + } + } + } + } + } + Pos--; + } + if (bolOnly && didMatch && CountX[1] == 0 && CountX[2] == 0) { + *OPos = 0; + *OLine = Row; + free(StateMap); + return B->LineIndented(Row); + } + if (StateMap) free(StateMap); + Row--; + } + return -1; +} + +static int FindPrevIndent(EBuffer *B, int &RowP, int &ColP, char &CharP, int Flags) { + STARTFUNC("FindPrevIndent{h_c.cpp}"); + LOG << "Flags: " << hex << Flags << dec << ENDLINE; + int StateLen; + hsState *StateMap = 0; + char *P; + int L; + int Count[4] = { + 0, // { } + 0, // ( ) + 0, // [ ] + 0, // if/else (one if for each else) + }; + +#define TEST_ZERO (Count[0] == 0 && Count[1] == 0 && Count[2] == 0\ + && Count[3] == 0) + + assert(RowP >= 0 && RowP < B->RCount); + L = B->RLine(RowP)->Count; + if (ColP >= L) + ColP = L - 1; + assert(ColP >= -1 && ColP <= L); + + char BolChar = ' '; + int BolCol = -1; + int BolRow = -1; + + while (RowP >= 0) { + + P = B->RLine(RowP)->Chars; + L = B->RLine(RowP)->Count; + StateMap = NULL; + if (B->GetMap(RowP, &StateLen, &StateMap) == 0) + { + LOG << "Can't get state maps" << ENDLINE; + ENDFUNCRC(0); + } + if (L > 0) while (ColP >= 0) { + LOG << "ColP: " << ColP << " State: " << (int)StateMap[ColP] << ENDLINE; + if (StateMap[ColP] == hsC_Normal) { + LOG << "CharP: " << BinChar(P[ColP]) << " BolChar: " << BinChar(BolChar) << + " BolRow: " << BolRow << + " BolCol: " << BolCol << + ENDLINE; + switch (CharP = P[ColP]) { + case '{': + if (BolChar == ':' || BolChar == ',') { + CharP = BolChar; + ColP = BolCol; + RowP = BolRow; + free(StateMap); + ENDFUNCRC(1); + } + if (TEST_ZERO) { + free(StateMap); + ENDFUNCRC(1); + } + Count[0]--; + break; + case '}': + if (BolChar == ':' || BolChar == ',') { + CharP = BolChar; + ColP = BolCol; + RowP = BolRow; + free(StateMap); + ENDFUNCRC(1); + } + if (BolChar == ';') { + CharP = BolChar; + ColP = BolCol; + RowP = BolRow; + free(StateMap); + ENDFUNCRC(1); + } + if (ColP == 0) { /* speed optimization */ + free(StateMap); + ENDFUNCRC(1); + } + if (TEST_ZERO && (Flags & FIND_ENDBLOCK)) { + free(StateMap); + ENDFUNCRC(1); + } + Count[0]++; + break; + case '(': + if (TEST_ZERO) { + free(StateMap); + ENDFUNCRC(1); + } + Count[1]--; + break; + case ')': + Count[1]++; + break; + case '[': + if (TEST_ZERO) { + free(StateMap); + ENDFUNCRC(1); + } + Count[2]--; + break; + case ']': + Count[2]++; + break; + case ':': + if (ColP >= 1 && P[ColP - 1] == ':') { // skip :: + ColP -= 2; + continue; + } + case ',': + case ';': + if (TEST_ZERO && BolChar == ' ') { + if ((CharP == ';' && (Flags & FIND_SEMICOLON)) + || (CharP == ',' && (Flags & FIND_COMMA)) + || (CharP == ':' && (Flags & FIND_COLON))) { + BolChar = CharP; + BolCol = ColP; + BolRow = RowP; + // this should be here + // if not say why ??? + //free(StateMap); + //return 1; + } + } + if (BolChar == ',' && CharP == ':') { + BolChar = ' '; + BolCol = -1; + BolRow = -1; + break; + } + if ((BolChar == ':' || BolChar == ',') + && (CharP == ';'/* || CharP == ','*/)) { + CharP = ':'; + ColP = BolCol; + RowP = BolRow; + free(StateMap); + ENDFUNCRC(1); + } + break; + case '?': + //if ((Flags & FIND_QUESTION)) { + if (BolChar == ':' || BolChar == ',') { + BolChar = ' '; + BolCol = -1; + BolRow = -1; + } + //} + break; + } + } else if (StateMap[ColP] == hsC_Keyword && (BolChar == ' ' || BolChar == ':')) { + if (L - ColP >= 2 && + IsState(StateMap + ColP, hsC_Keyword, 2) && + memcmp(P + ColP, "if", 2) == 0) + { + //puts("\nif"); + if (Count[3] > 0) + Count[3]--; + if (Flags & FIND_IF) { + if (TEST_ZERO) { + CharP = 'i'; + free(StateMap); + ENDFUNCRC(1); + } + } + } + if (L - ColP >= 4 && + IsState(StateMap + ColP, hsC_Keyword, 4) && + memcmp(P + ColP, "else", 4) == 0) + { + //puts("\nelse\x7"); + if (Flags & FIND_ELSE) { + if (TEST_ZERO) { + CharP = 'e'; + free(StateMap); + ENDFUNCRC(1); + } + } + Count[3]++; + } + if (TEST_ZERO) { + + if ((Flags & FIND_FOR) && + L - ColP >= 3 && + IsState(StateMap + ColP, hsC_Keyword, 3) && + memcmp(P + ColP, "for", 3) == 0) + { + CharP = 'f'; + free(StateMap); + ENDFUNCRC(1); + } + if ((Flags & FIND_WHILE) && + L - ColP >= 5 && + IsState(StateMap + ColP, hsC_Keyword, 5) && + memcmp(P + ColP, "while", 5) == 0) + { + CharP = 'w'; + free(StateMap); + ENDFUNCRC(1); + } + if ((Flags & FIND_SWITCH) && + L - ColP >= 6 && + IsState(StateMap + ColP, hsC_Keyword, 6) && + memcmp(P + ColP, "switch", 6) == 0) + { + CharP = 's'; + free(StateMap); + ENDFUNCRC(1); + } + if (((Flags & FIND_CASE) || (BolChar == ':')) && + (L - ColP >= 4 && + IsState(StateMap + ColP, hsC_Keyword, 4) && + memcmp(P + ColP, "case", 4) == 0) || + ((L - ColP >= 7) && + IsState(StateMap + ColP, hsC_Keyword, 7) && + memcmp(P + ColP, "default", 7) == 0)) + { + CharP = 'c'; + if (BolChar == ':') { + CharP = BolChar; + ColP = BolCol; + RowP = BolRow; + } + free(StateMap); + ENDFUNCRC(1); + } + if (((Flags & FIND_CLASS) || (BolChar == ':')) && + (L - ColP >= 5 && + IsState(StateMap + ColP, hsC_Keyword, 5) && + memcmp(P + ColP, "class", 5) == 0)) + { + CharP = 'l'; + if (BolChar == ':') { + CharP = BolChar; + ColP = BolCol; + RowP = BolRow; + } + free(StateMap); + ENDFUNCRC(1); + } + if (((Flags & FIND_CLASS) || (BolChar == ':')) && + ((L - ColP >= 6 && + IsState(StateMap + ColP, hsC_Keyword, 6) && + memcmp(P + ColP, "public", 6) == 0) || + ((L - ColP >= 7) && + IsState(StateMap + ColP, hsC_Keyword, 7) && + memcmp(P + ColP, "private", 7) == 0) || + ((L - ColP >= 9) && + IsState(StateMap + ColP, hsC_Keyword, 9) && + memcmp(P + ColP, "protected", 9) == 0))) + { + CharP = 'p'; + if (BolChar == ':') { + CharP = BolChar; + ColP = BolCol; + RowP = BolRow; + } + free(StateMap); + ENDFUNCRC(1); + } + } + } + ColP--; + } + free(StateMap); + if (BolChar != ' ' && BolChar != ':' && BolChar != ',') { + CharP = BolChar; + ColP = BolCol; + ENDFUNCRC(1); + } + RowP--; + if (RowP >= 0) { + L = B->RLine(RowP)->Count; + ColP = L - 1; + } + } +#undef TEST_ZERO + ENDFUNCRC(0); +} + +#define SKIP_FORWARD 0 +#define SKIP_BACK 1 +#define SKIP_MATCH 2 +#define SKIP_LINE 4 +#define SKIP_TOBOL 8 + +static int SkipWhite(EBuffer *B, int Bottom, int &Row, int &Col, int Flags) { + char *P; + int L; + int StateLen; + hsState *StateMap; + int Count[3] = { 0, 0, 0 }; + + assert (Row >= 0 && Row < B->RCount); + L = B->RLine(Row)->Count; + if (Col >= L) + Col = L; + assert (Col >= -1 && Col <= L) ; + + while (Row >= 0 && Row < B->RCount) { + P = B->RLine(Row)->Chars; + L = B->RLine(Row)->Count; + StateMap = NULL; + if (B->GetMap(Row, &StateLen, &StateMap) == 0) + return 0; + + if (L > 0) + for ( ; Col >= 0 && Col < L; + Col += ((Flags & SKIP_BACK) ? -1 : +1)) { + if (P[Col] == ' ' || P[Col] == '\t') + continue; + if (StateMap[Col] != hsC_Normal && + StateMap[Col] != hsC_Keyword && + StateMap[Col] != hsC_String1 && + StateMap[Col] != hsC_String2) + continue; + if (StateMap[Col] == hsC_Normal && (Flags & SKIP_MATCH)) { + switch (P[Col]) { + case '{': Count[0]--; continue; + case '}': Count[0]++; continue; + case '(': Count[1]--; continue; + case ')': Count[1]++; continue; + case '[': Count[2]--; continue; + case ']': Count[2]++; continue; + } + } + if (Count[0] == 0 && Count[1] == 0 && Count[2] == 0 + && !(Flags & SKIP_TOBOL)) { + free(StateMap); + return 1; + } + } + free(StateMap); + if (Count[0] == 0 && Count[1] == 0 && Count[2] == 0 && (Flags & SKIP_TOBOL)) + return 1; + if (Flags & SKIP_LINE) { + return 1; + } + if (Flags & SKIP_BACK) { + Row--; + if (Row >= 0) { + L = B->RLine(Row)->Count; + Col = L - 1; + } + } else { + if (Row + 1 >= Bottom) + return 1; + Row++; + Col = 0; + } + } + return 0; +} + + +static int IndentNormal(EBuffer *B, int Line, int /*StateLen*/, hsState * /*StateMap*/) { + STARTFUNC("IndentNormal{h_c.cpp}"); + int I = 0; + int Pos, L; + + if (LookAt(B, Line, 0, "case", hsC_Keyword) || + LookAt(B, Line, 0, "default", hsC_Keyword)) + { + I = SearchBackMatch(-1, B, Line - 1, hsC_Normal, "{", "}", &Pos, &L) + C_CASE_OFS; + return I; + } else if (LookAt(B, Line, 0, "public:", hsC_Keyword, 0) || + LookAt(B, Line, 0, "private:", hsC_Keyword, 0) || + LookAt(B, Line, 0, "protected:", hsC_Keyword, 0)) + { + I = SearchBackMatch(-1, B, Line - 1, hsC_Normal, "{", "}", &Pos, &L) + C_CLASS_OFS; + return I; + } else if (LookAt(B, Line, 0, "else", hsC_Keyword)) { + I = SearchBackMatch(-1, B, Line - 1, hsC_Keyword, "if", "else", &Pos, &L, 1); + return I; + } else if (LookAt(B, Line, 0, "}", hsC_Normal, 0)) { + I = SearchBackMatch(-1, B, Line - 1, hsC_Normal, "{", "}", &Pos, &L, 0, 1); + return I; + } else if (LookAt(B, Line, 0, ")", hsC_Normal, 0)) { + I = SearchBackMatch(-1, B, Line - 1, hsC_Normal, "(", ")", &Pos, &L); + if (C_PAREN_DELTA >= 0) + return I + C_PAREN_DELTA; + else + return Pos; + } else if (LookAt(B, Line, 0, "]", hsC_Normal, 0)) { + I = SearchBackMatch(-1, B, Line - 1, hsC_Normal, "[", "]", &Pos, &L); + if (C_PAREN_DELTA >= 0) + return I + C_PAREN_DELTA; + else + return Pos; + } else { + char CharP = ' '; + // char FirstCharP = ' '; + int RowP = Line; + int ColP = -1; + int PrevRowP = RowP; + int PrevColP = ColP; + int FirstRowP; + int FirstColP; + int ContinuationIndent = 0; + + if (SkipWhite(B, Line, PrevRowP, PrevColP, SKIP_BACK) != 1) + return 0; + + PrevColP++; + LOG << "PrevRowP=" << PrevRowP << ", PrevColP=" << PrevColP << ENDLINE; + + if (FindPrevIndent(B, RowP, ColP, CharP, + FIND_IF | + FIND_ELSE | + FIND_FOR | + FIND_WHILE | + FIND_SWITCH | + FIND_CASE | + //FIND_CLASS | + FIND_COLON | + FIND_SEMICOLON | + FIND_COMMA | + FIND_ENDBLOCK) != 1) + { + if (RowP != PrevRowP) + ContinuationIndent = C_CONTINUATION; + I = 0; + if (LookAt(B, Line, 0, "{", hsC_Normal, 0)) { + I += C_BRACE_OFS; + ContinuationIndent = 0; + } + return I + ContinuationIndent; + } + + FirstRowP = RowP; + FirstColP = ColP; + // FirstCharP = CharP; + + LOG << "FirstRowP=" << FirstRowP << ", FirstColP=" << FirstColP << + ", CharP=" << BinChar(CharP) << ENDLINE; + + switch (CharP) { + case 'c': + I = B->LineIndented(RowP) + C_CONTINUATION; + return I; + + case '(': + case '[': + if (C_PAREN_DELTA >= 0) { + I = B->LineIndented(FirstRowP) + C_PAREN_DELTA; + } else { + ColP++; + if (SkipWhite(B, Line, RowP, ColP, SKIP_FORWARD | SKIP_LINE) != 1) + return 0; + I = B->ScreenPos(B->RLine(RowP), ColP); + } + return I; + + case '{': + ColP++; + if (((PrevRowP != RowP) || + ((PrevRowP == RowP) && (PrevColP != ColP))) + && FirstRowP != PrevRowP) + ContinuationIndent = C_CONTINUATION; + ColP--; ColP--; + if (SkipWhite(B, Line, RowP, ColP, SKIP_BACK | SKIP_TOBOL | SKIP_MATCH) != 1) + return 0; + I = B->LineIndented(RowP); + if (B->LineIndented(FirstRowP) <= C_FIRST_WIDTH) + I += C_FIRST_INDENT; + else + I += C_INDENT; + PRINTF(("'{' indent : Line=%d, RowP=%d, ColP=%d, CharP=%c\n", Line, RowP, ColP, CharP)); + + if (LookAt(B, Line, 0, "{", hsC_Normal, 0)) + I -= C_BRACE_OFS; + else + I += ContinuationIndent; + + return I; + case ',': + I = B->LineIndented(FirstRowP); + return I; + case '}': + ColP++; + ColP++; + /*---nobreak---*/ + case ';': + ColP--; + if (FindPrevIndent(B, RowP, ColP, CharP, + ((CharP == ',') ? FIND_COMMA | FIND_COLON : + //(CharP == ';') ? FIND_SEMICOLON | FIND_COLON : + FIND_SEMICOLON | FIND_COLON)) != 1) + { + if (FirstRowP != PrevRowP) + ContinuationIndent = C_CONTINUATION; + I = 0; + if (LookAt(B, Line, 0, "{", hsC_Normal, 0)) { + I += C_BRACE_OFS; + ContinuationIndent = 0; + } + return I + ContinuationIndent; + } + PRINTF(("';' Line=%d, RowP=%d, ColP=%d, CharP=%c\n", Line, RowP, ColP, CharP)); + + LOG << " CharP now: " << BinChar(CharP) << ENDLINE; + switch (CharP) { + case ',': + case ';': + case '{': + case ':': + ColP++; + if (SkipWhite(B, Line, RowP, ColP, SKIP_FORWARD) != 1) + return 0; + //ColP--; + //if (SkipWhite(B, RowP, ColP, SKIP_BACK) != 1) + //if (CharP == ':') { + // I -= C_COLON_OFS; + //} + PRINTF(("';' indent : Line=%d, RowP=%d, ColP=%d, CharP=%c\n", Line, RowP, ColP, CharP)); + I = B->LineIndented(RowP); + if (((PrevRowP != RowP) || + ((PrevRowP == RowP) && (PrevColP != ColP))) + && FirstRowP != PrevRowP) + ContinuationIndent = C_CONTINUATION; + + if (LookAt(B, Line, 0, "{", hsC_Normal, 0)) { + //I -= C_BRACE_OFS; + ContinuationIndent = 0; + } + if (LookAt(B, Line, 0, "{", hsC_Normal, 0) + && LookAt(B, RowP, ColP, "{", hsC_Normal, 0)) + I -= 0; //C_BRACE_OFS; + else if (LookAt(B, Line, 0, "{", hsC_Normal, 0) + && !LookAt(B, RowP, ColP, "{", hsC_Normal, 0)) + I += C_BRACE_OFS; + else if (!LookAt(B, Line, 0, "{", hsC_Normal, 0) + && LookAt(B, RowP, ColP, "{", hsC_Normal, 0)) + I -= C_BRACE_OFS; + break; + case '(': + ColP++; + if (SkipWhite(B, Line, RowP, ColP, SKIP_FORWARD | SKIP_LINE) != 1) + return 0; + I = B->ScreenPos(B->RLine(RowP), ColP); + break; + default: + I = B->LineIndented(RowP); + break; + } + PRINTF(("';' -- indent : Line=%d, RowP=%d, ColP=%d, CharP=%c\n", Line, RowP, ColP, CharP)); + + // else + // if (LookAt(B, Line, 0, "{", hsC_Normal, 0)) + // I += C_INDENT - C_BRACE_OFS; + + return I + ContinuationIndent; + + case ':': + ColP--; + if (FindPrevIndent(B, RowP, ColP, CharP, FIND_SEMICOLON | FIND_COLON | FIND_QUESTION | FIND_CLASS | FIND_CASE) != 1) { + if (FirstRowP != PrevRowP) + ContinuationIndent = C_CONTINUATION; + return 0 + ContinuationIndent; + } + + PRINTF(("':' Line=%d, RowP=%d, ColP=%d, CharP=%c\n", Line, RowP, ColP, CharP)); + + switch (CharP) { + case ':': + //ColP++; + /*if (SkipWhite(B, Line, RowP, ColP, SKIP_FORWARD) != 1) + return 0; + I = B->LineIndented(RowP);// - C_COLON_OFS; + PRINTF(("':' 0 indent : Line=%d, RowP=%d, ColP=%d, CharP=%c\n", Line, RowP, ColP, CharP)); + break;*/ + case '{': + case ';': + ColP++; + if (SkipWhite(B, Line, RowP, ColP, SKIP_FORWARD) != 1) + return 0; + I = B->LineIndented(RowP); + PRINTF(("!!! FirstRowP=%d, PrevRowP=%d, RowP=%d, I=%d\n", FirstRowP, PrevRowP, RowP, I)); + PRINTF(("!!! FirstColP=%d, PrevColP=%d, ColP=%d\n", FirstColP, PrevColP, ColP)); + if (CheckLabel(B, RowP)) + I -= C_COLON_OFS; + else if (PrevRowP == RowP && FirstRowP == PrevRowP && FirstColP + 1 == PrevColP) + I += C_CONTINUATION; + if (LookAt(B, Line, 0, "{", hsC_Normal, 0) + && LookAt(B, RowP, ColP, "{", hsC_Normal, 0)) + I -= 0;//C_BRACE_OFS; + else if (LookAt(B, Line, 0, "{", hsC_Normal, 0) + && !LookAt(B, RowP, ColP, "{", hsC_Normal, 0)) + I += C_BRACE_OFS; + else if (!LookAt(B, Line, 0, "{", hsC_Normal, 0) + && LookAt(B, RowP, ColP, "{", hsC_Normal, 0)) + I -= C_BRACE_OFS; + PRINTF(("':' 1 indent : Line=%d, RowP=%d, ColP=%d, CharP=%c\n", Line, RowP, ColP, CharP)); + break; + case 'p': + ColP++; + //if (SkipWhite(B, Line, RowP, ColP, SKIP_FORWARD) != 1) + // return 0; + I = B->LineIndented(RowP) + C_CLASS_DELTA; + // if (FirstRowP == RowP) { + // I += C_CLASS_DELTA; + /// if (LookAt(B, Line, 0, "{", hsC_Normal, 0)) { + /// I += C_INDENT - C_BRACE_OFS; + /// } + // } + PRINTF(("':' 2 indent : Line=%d, RowP=%d, ColP=%d, CharP=%c\n", Line, RowP, ColP, CharP)); + break; + case 'l': + ColP++; + I = B->LineIndented(RowP) + C_BRACE_OFS; + //C_CLASS_OFS + C_CLASS_DELTA; + break; + case 'c': + ColP++; + // if (SkipWhite(B, Line, RowP, ColP, SKIP_FORWARD) != 1) + // return 0; + I = B->LineIndented(RowP) + C_CASE_DELTA; + // if (FirstRowP == RowP) { + // I += C_CASE_DELTA; + /// if (LookAt(B, Line, 0, "{", hsC_Normal, 0)) { + /// I += C_INDENT - C_BRACE_OFS; + /// } + // } + + PRINTF(("':' 3 indent : Line=%d, RowP=%d, ColP=%d, CharP=%c\n", Line, RowP, ColP, CharP)); + break; + default: + I = B->LineIndented(RowP); + break; + } + if (((PrevRowP != RowP) || + ((PrevRowP == RowP) && (PrevColP != ColP))) + && FirstRowP != PrevRowP) + ContinuationIndent = C_CONTINUATION; + if (LookAt(B, Line, 0, "{", hsC_Normal, 0)) { + //I -= C_INDENT - C_BRACE_OFS; + ContinuationIndent = 0; + } + PRINTF(("':' -- indent : Line=%d, RowP=%d, ColP=%d, CharP=%c\n", Line, RowP, ColP, CharP)); + return I + ContinuationIndent; + + case 'i': + case 's': + case 'f': + case 'e': + case 'w': + I = B->LineIndented(RowP); + switch (CharP) { + case 'i': ColP += 2; break; // if + case 'f': ColP += 3; break; // for + case 'e': ColP += 4; break; // else + case 'w': ColP += 5; break; // while + case 's': ColP += 6; break; + } + PRINTF(("'ifews' -- indent 1: Line=%d, RowP=%d, ColP=%d, CharP=%c\n", Line, RowP, ColP, CharP)); + if (SkipWhite(B, Line, RowP, ColP, + SKIP_FORWARD | (CharP != 'e' ? SKIP_MATCH : 0)) != 1) + return 0; + if (RowP >= Line) { + RowP = Line; + ColP = -1; + } else + ColP--; + if (SkipWhite(B, Line, RowP, ColP, SKIP_BACK) != 1) + return 0; + ColP++; + PRINTF(("'ifews' -- indent 2: Line=%d, RowP=%d, ColP=%d, CharP=%c\n", Line, RowP, ColP, CharP)); + + if (((PrevRowP != RowP) || + ((PrevRowP == RowP) && (PrevColP != ColP))) + && FirstRowP != PrevRowP) + ContinuationIndent = C_CONTINUATION; + + I += C_INDENT; + + if (LookAt(B, Line, 0, "{", hsC_Normal, 0)) { + I -= C_INDENT - C_BRACE_OFS; + ContinuationIndent = 0; + } + + return I + ContinuationIndent; + + // default: return 0; + } + } + return 0; +} + +static int IndentComment(EBuffer *B, int Row, int /*StateLen*/, hsState * /*StateMap*/) { + int I = 0, R; + + //puts("Comment"); + + if (Row > 0) { + R = Row - 1; + while (R >= 0) { + if (B->RLine(R)->Count == 0) R--; + else { + I = B->LineIndented(R); + break; + } + } + if (B->RLine(Row - 1)->StateE == hsC_Comment) + if (LookAt(B, Row - 1, I, "/*", hsC_Comment, 0)) I += C_COMMENT_DELTA; + if (B->RLine(Row - 1)->StateE == hsC_CPP_Comm) + if (LookAt(B, Row - 1, I, "/*", hsC_CPP_Comm, 0)) I += C_COMMENT_DELTA; + } + return I; +} + +static int IndentCPP(EBuffer *B, int Line, int /*StateLen*/, hsState * /*StateMap*/) { + if (LookAt(B, Line, 0, "#", hsC_CPP, 0)) + return 0; + else + return C_INDENT; +} + +int Indent_C(EBuffer *B, int Line, int PosCursor) { + int I; + hsState *StateMap = NULL; + int StateLen = 0; + int OI; + + OI = I = B->LineIndented(Line); + if (Line == 0) { + I = 0; + } else { + if (I != 0) B->IndentLine(Line, 0); + if (B->GetMap(Line, &StateLen, &StateMap) == 0) return 0; + + switch (B->RLine(Line - 1)->StateE) { + case hsC_Comment: + case hsC_CPP_Comm: + I = IndentComment(B, Line, StateLen, StateMap); + break; + case hsC_CPP: + /*case hsC_CPP_Comm:*/ + case hsC_CPP_String1: + case hsC_CPP_String2: + case hsC_CPP_ABrace: + I = C_INDENT; + break; + default: + if (StateLen > 0) { // line is not empty + if (StateMap[0] == hsC_CPP || StateMap[0] == hsC_CPP_Comm || + StateMap[0] == hsC_CPP_String1 || StateMap[0] == hsC_CPP_String2 || + StateMap[0] == hsC_CPP_ABrace) + { + I = IndentCPP(B, Line, StateLen, 0); + } else { + I = IndentNormal(B, Line, StateLen, StateMap); + if ((StateMap[0] == hsC_Comment + || StateMap[0] == hsC_CommentL + || StateMap[0] == hsC_CPP_Comm) + && ((LookAt(B, Line, 0, "/*", hsC_Comment, 0) + || LookAt(B, Line, 0, "/*", hsC_CPP_Comm, 0) + || LookAt(B, Line, 0, "//", hsC_CommentL, 0)))) + { + I += C_COMMENT_OFS; + } else if (CheckLabel(B, Line)) { + if (LookAt(B, Line, 0, "case", hsC_Keyword) || + LookAt(B, Line, 0, "default", hsC_Keyword) || + LookAt(B, Line, 0, "public:", hsC_Keyword, 0) || + LookAt(B, Line, 0, "private:", hsC_Keyword, 0) || + LookAt(B, Line, 0, "protected:", hsC_Keyword, 0)) + ; + else + I += C_COLON_OFS; + } //else if (LookAt(B, Line, 0, "{", hsC_Normal, 0)) { + // I -= C_INDENT - C_BRACE_OFS; + //} + } + } else { + I = IndentNormal(B, Line, 0, NULL); + } + break; + } + } + if (StateMap) + free(StateMap); + if (I >= 0) + B->IndentLine(Line, I); + else + I = 0; + if (PosCursor == 1) { + int X = B->CP.Col; + + X = X - OI + I; + if (X < I) X = I; + if (X < 0) X = 0; + if (X > B->LineLen(Line)) { + X = B->LineLen(Line); + if (X < I) X = I; + } + if (B->SetPosR(X, Line) == 0) return 0; + } else if (PosCursor == 2) { + if (B->SetPosR(I, Line) == 0) return 0; + } + return 1; +} +#endif +#endif diff --git a/src/h_catbs.cpp b/src/h_catbs.cpp new file mode 100644 index 0000000..13b12bf --- /dev/null +++ b/src/h_catbs.cpp @@ -0,0 +1,52 @@ +/* h_catbs.cpp + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#include "fte.h" + +#ifdef CONFIG_HILIT_CATBS + +#define hsBS_Normal 1 + +// this is for viewing only, do not try to edit or anything. + +int Hilit_CATBS(EBuffer *BF, int /*LN*/, PCell B, int Pos, int Width, ELine *Line, hlState &State, hsState *StateMap, int *ECol) { + ChColor *Colors = BF->Mode->fColorize->Colors; + HILIT_VARS(Colors[CLR_Normal], Line); + int CL = 0; //(LN == BF->VToR(BF->CP.Row)) ? 1 : 0; + + for (i = 0; i < Line->Count;) { + IF_TAB() else { + switch (State) { + default: + case hsBS_Normal: + Color = Colors[CLR_Normal]; + while (!CL && len >= 2 && p[1] == '\b') { + if (len > 2 && p[0] == p[2]) { // bold + Color = Colors[CLR_Keyword]; + NextChar(); + NextChar(); + C -= 2; + } else if (p[0] == '_') { // underline + Color = Colors[CLR_Symbol]; + NextChar(); + NextChar(); + C -= 2; + break; + } else + break; + } + ColorNext(); + continue; + } + } + } + *ECol = C; + return 0; +} +#endif diff --git a/src/h_diff.cpp b/src/h_diff.cpp new file mode 100644 index 0000000..603de8e --- /dev/null +++ b/src/h_diff.cpp @@ -0,0 +1,55 @@ +/* h_diff.cpp + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#include "fte.h" + +#ifdef CONFIG_HILIT_DIFF + +int Hilit_DIFF(EBuffer *BF, int /*LN*/, PCell B, int Pos, int Width, ELine* Line, hlState& State, hsState *StateMap, int *ECol) { + ChColor *Colors = BF->Mode->fColorize->Colors; + HILIT_VARS(Colors[CLR_Normal], Line); + + if (Line->Count > 0) { + switch (Line->Chars[0]) { + case '>': + case '+': Color = Colors[CLR_New]; break; + case '<': + case '-': Color = Colors[CLR_Old]; break; + case '!': Color = Colors[CLR_Changed]; break; + default: Color = Colors[CLR_Normal]; break; + } + } + + if (ExpandTabs) { /* use slow mode */ + for (i = 0; i < Line->Count;) { + IF_TAB() else { + ColorNext(); + } + } + } else { /* fast mode */ + if (Pos < Line->Count) { + if (Pos + Width < Line->Count) { + if (B) + MoveMem(B, 0, Width, Line->Chars + Pos, Color, Width); + if (StateMap) + memset(StateMap, State, Line->Count); + } else { + if (B) + MoveMem(B, 0, Width, Line->Chars + Pos, Color, Line->Count - Pos); + if (StateMap) + memset(StateMap, State, Line->Count); + } + } + C = Line->Count; + } + State = 0; + *ECol = C; + return 0; +} +#endif diff --git a/src/h_fte.cpp b/src/h_fte.cpp new file mode 100644 index 0000000..18d57b8 --- /dev/null +++ b/src/h_fte.cpp @@ -0,0 +1,170 @@ +/* h_fte.cpp + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#include "fte.h" + +#ifdef CONFIG_HILIT_FTE + +#define hsFTE_Normal 0 +#define hsFTE_Comment 1 +#define hsFTE_Keyword 4 +#define hsFTE_String1 10 +#define hsFTE_String2 11 +#define hsFTE_CPP 12 +#define hsFTE_Regexp 15 +#define hsFTE_KeySpec 16 + +int Hilit_FTE(EBuffer *BF, int /*LN*/, PCell B, int Pos, int Width, ELine *Line, hlState &State, hsState *StateMap, int *ECol) { + ChColor *Colors = BF->Mode->fColorize->Colors; + int j = 0; + HILIT_VARS(Colors[CLR_Normal], Line); + int len1 = len; + char *last = p + len1 - 1; + + C = 0; + NC = 0; + + for (i = 0; i < Line->Count;) { + IF_TAB() else { + switch(State) { + default: + case hsFTE_Normal: + if (isalpha(*p) || *p == '_') { + j = 0; + while (((i + j) < Line->Count) && + (isalnum(Line->Chars[i+j]) || + (Line->Chars[i + j] == '_')) + ) j++; + if (BF->GetHilitWord(j, &Line->Chars[i], Color)) { + State = hsFTE_Keyword; + } else { + Color = Colors[CLR_Normal]; + State = hsFTE_Normal; + } + if (StateMap) + memset(StateMap + i, State, j); + if (B) + MoveMem(B, C - Pos, Width, Line->Chars + i, Color, j); + i += j; + len -= j; + p += j; + C += j; + State = hsFTE_Normal; + continue; + } else if (*p == '#') { + State = hsFTE_Comment; + Color = Colors[CLR_Comment]; + goto hilit; + } else if (*p == '%') { + State = hsFTE_CPP; + Color = Colors[CLR_CPreprocessor]; + goto hilit; + } else if (isdigit(*p)) { + Color = Colors[CLR_Number]; + ColorNext(); + while (len && (isdigit(*p) || *p == 'e' || *p == 'E' || *p == '.')) ColorNext(); + if (len && (toupper(*p) == 'U')) ColorNext(); + if (len && (toupper(*p) == 'L')) ColorNext(); + continue; + } else if (*p == '\'') { + State = hsFTE_String1; + Color = Colors[CLR_String]; + goto hilit; + } else if (*p == '[') { + State = hsFTE_KeySpec; + Color = Colors[CLR_Command]; + goto hilit; + } else if (*p == '"') { + State = hsFTE_String2; + Color = Colors[CLR_String]; + goto hilit; + } else if (*p == '/') { + State = hsFTE_Regexp; + Color = Colors[CLR_Regexp]; + goto hilit; + } else if (ispunct(*p)) { + Color = Colors[CLR_Punctuation]; + ColorNext(); + continue; + } + Color = Colors[CLR_Normal]; + ColorNext(); + continue; + case hsFTE_Comment: + Color = Colors[CLR_Comment]; + goto hilit; + case hsFTE_CPP: + Color = Colors[CLR_CPreprocessor]; + goto hilit; + case hsFTE_String1: + Color = Colors[CLR_String]; + if ((len >= 2) && (*p == '\\')) { + hilit2: + ColorNext(); + hilit: + ColorNext(); + continue; + } else if (*p == '\'') { + ColorNext(); + State = hsFTE_Normal; + continue; + } + goto hilit; + case hsFTE_String2: + Color = Colors[CLR_String]; + if ((len >= 2) && (*p == '\\')) { + goto hilit2; + } else if (*p == '"') { + ColorNext(); + State = hsFTE_Normal; + continue; + } + goto hilit; + case hsFTE_KeySpec: + Color = Colors[CLR_Command]; + if ((len >= 2) && (*p == '\\')) { + goto hilit2; + } else if (*p == ']') { + ColorNext(); + State = hsFTE_Normal; + continue; + } + goto hilit; + case hsFTE_Regexp: + Color = Colors[CLR_Regexp]; + if ((len >= 2) && (*p == '\\')) { + goto hilit2; + } else if (*p == '/') { + ColorNext(); + State = hsFTE_Normal; + continue; + } + goto hilit; + } + } + } + + if (State == hsFTE_Comment) + State = hsFTE_Normal; + + if ((len1 == 0) || (*last != '\\')) { + switch(State) { + case hsFTE_CPP: + case hsFTE_String1: + case hsFTE_String2: + case hsFTE_KeySpec: + case hsFTE_Regexp: + State = hsFTE_Normal; + break; + } + } + *ECol = C; + return 0; +} +#endif diff --git a/src/h_html.cpp b/src/h_html.cpp new file mode 100644 index 0000000..58862fb --- /dev/null +++ b/src/h_html.cpp @@ -0,0 +1,143 @@ +/* h_html.cpp + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#include "fte.h" + +#ifdef CONFIG_HILIT_HTML + +#define hsHTML_Normal 0 +#define hsHTML_Command 1 +#define hsHTML_String1 2 +#define hsHTML_String2 3 +#define hsHTML_Char 4 +#define hsHTML_Slashed 5 +#define hsHTML_Comment 6 + +int Hilit_HTML(EBuffer *BF, int /*LN*/, PCell B, int Pos, int Width, ELine *Line, hlState &State, hsState *StateMap, int *ECol) { + ChColor *Colors = BF->Mode->fColorize->Colors; + HILIT_VARS(Colors[CLR_Normal], Line); + int j; + + for (i = 0; i < Line->Count;) { + IF_TAB() else { + switch (State) { + case hsHTML_Normal: + Color = Colors[CLR_Normal]; + if (*p == '<') { + State = hsHTML_Command; + Color = Colors[CLR_Command]; + ColorNext(); + if ((len > 0) && (*p == '/')) ColorNext(); + continue; + } else if (*p == '&') { + State = hsHTML_Char; + Color = Colors[CLR_Symbol]; + } + goto hilit; + case hsHTML_Slashed: + Color = Colors[CLR_Tag]; + if (*p == '/') { + Color = Colors[CLR_Command]; + ColorNext(); + State = hsHTML_Normal; + continue; + } + goto hilit; + case hsHTML_Command: + Color = Colors[CLR_Command]; + if (isalpha(*p) || *p == '_') { + j = 0; + while (((i + j) < Line->Count) && + (isalnum(Line->Chars[i+j]) || + (Line->Chars[i + j] == '_')) + ) j++; + if (BF->GetHilitWord(j, &Line->Chars[i], Color, 1)) { + } + if (StateMap) + memset(StateMap + i, State, j); + if (B) + MoveMem(B, C - Pos, Width, Line->Chars + i, Color, j); + i += j; + len -= j; + p += j; + C += j; + Color = Colors[CLR_Command]; + continue; + } else if (*p == '-' && len > 1 && p[1] == '-') { + State = hsHTML_Comment; + Color = Colors[CLR_Comment]; + ColorNext(); + goto hilit; + } else if (*p == '"') { + State = hsHTML_String2; + Color = Colors[CLR_String]; + goto hilit; + } else if (*p == '\'') { + State = hsHTML_String1; + Color = Colors[CLR_String]; + goto hilit; + } else if (*p == '>') { + ColorNext(); + State = hsHTML_Normal; + continue; + } else if (*p == '/') { + ColorNext(); + State = hsHTML_Slashed; + continue; + } + goto hilit; + case hsHTML_String2: + Color = Colors[CLR_String]; + if (*p == '"') { + ColorNext(); + State = hsHTML_Command; + continue; + } + goto hilit; + case hsHTML_String1: + Color = Colors[CLR_String]; + if (*p == '\'') { + ColorNext(); + State = hsHTML_Command; + continue; + } + goto hilit; + case hsHTML_Char: + Color = Colors[CLR_Symbol]; + if (*p == ';' || *p == ' ' || *p == '<') { + ColorNext(); + State = hsHTML_Normal; + continue; + } + goto hilit; + case hsHTML_Comment: + Color = Colors[CLR_Comment]; + if (*p == '-' && len > 1 && p[1] == '-') { + ColorNext(); + ColorNext(); + State = hsHTML_Command; + continue; + } + goto hilit; + default: + State = hsHTML_Normal; + Color = Colors[CLR_Normal]; + hilit: + ColorNext(); + continue; + } + } + } + if (State == hsHTML_Char) + State = hsHTML_Normal; + *ECol = C; + return 0; +} + +#endif diff --git a/src/h_ipf.cpp b/src/h_ipf.cpp new file mode 100644 index 0000000..6e483cd --- /dev/null +++ b/src/h_ipf.cpp @@ -0,0 +1,107 @@ +/* h_ipf.cpp + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#include "fte.h" + +#ifdef CONFIG_HILIT_IPF + +#define hsIPF_Normal 0 +#define hsIPF_Symbol 1 +#define hsIPF_Tag 2 +#define hsIPF_Control 3 +#define hsIPF_String 4 + +int Hilit_IPF(EBuffer *BF, int /*LN*/, PCell B, int Pos, int Width, ELine *Line, hlState &State, hsState *StateMap, int *ECol) { + ChColor *Colors = BF->Mode->fColorize->Colors; + HILIT_VARS(Colors[CLR_Normal], Line); + int j; + + C = 0; + NC = 0; + for (i = 0; i < Line->Count;) { + IF_TAB() else { + switch (State) { + case hsIPF_Normal: + Color = Colors[CLR_Normal]; + if (i == 0 && *p == '.') { + State = hsIPF_Control; + Color = Colors[CLR_Control]; + } else if (*p == ':') { + State = hsIPF_Tag; + Color = Colors[CLR_Tag]; + } else if (*p == '&') { + State = hsIPF_Symbol; + Color = Colors[CLR_Symbol]; + } + goto hilit; + case hsIPF_Tag: + Color = Colors[CLR_Tag]; + if (isalpha(*p) || *p == '_') { + j = 0; + while (((i + j) < Line->Count) && + (isalnum(Line->Chars[i+j]) || + (Line->Chars[i + j] == '_')) + ) j++; + if (BF->GetHilitWord(j, &Line->Chars[i], Color, 1)) { + } + if (StateMap) + memset(StateMap + i, State, j); + if (B) + MoveMem(B, C - Pos, Width, Line->Chars + i, Color, j); + i += j; + len -= j; + p += j; + C += j; + Color = Colors[CLR_Tag]; + continue; + } else if (*p == '\'') { + State = hsIPF_String; + Color = Colors[CLR_String]; + goto hilit; + } else if (*p == '.') { + ColorNext(); + State = hsIPF_Normal; + continue; + } + goto hilit; + case hsIPF_String: + Color = Colors[CLR_String]; + if (*p == '\'') { + ColorNext(); + State = hsIPF_Tag; + continue; + } + goto hilit; + case hsIPF_Symbol: + Color = Colors[CLR_Symbol]; + if (*p == '.') { + ColorNext(); + State = hsIPF_Normal; + continue; + } + goto hilit; + case hsIPF_Control: + State = hsIPF_Control; + Color = Colors[CLR_Control]; + goto hilit; + default: + State = hsIPF_Normal; + Color = Colors[CLR_Normal]; + hilit: + ColorNext(); + continue; + } + } + } + if (State == hsIPF_Symbol || State == hsIPF_Control || State == hsIPF_String) + State = hsIPF_Normal; + *ECol = C; + return 0; +} +#endif diff --git a/src/h_make.cpp b/src/h_make.cpp new file mode 100644 index 0000000..e32f411 --- /dev/null +++ b/src/h_make.cpp @@ -0,0 +1,72 @@ +/* h_make.cpp + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#include "fte.h" + +#ifdef CONFIG_HILIT_MAKE + +#define hsMAKE_Normal 0 +#define hsMAKE_Comment 1 +#define hsMAKE_DotCmd 2 +#define hsMAKE_Command 3 + +int Hilit_MAKE(EBuffer *BF, int /*LN*/, PCell B, int Pos, int Width, ELine *Line, hlState &State, hsState *StateMap, int *ECol) { + ChColor *Colors = BF->Mode->fColorize->Colors; + HILIT_VARS(Colors[CLR_Normal], Line); + int len1 = len; + char *last = p + len1 - 1; + + for(i = 0; i < Line->Count;) { + if (i == 0 && *p == 9) { + State = hsMAKE_Command; + Color = Colors[CLR_Command]; + } + IF_TAB() else { + if (i == 0) { + if (*p == '.') { + State = hsMAKE_DotCmd; + Color = Colors[CLR_Directive]; + goto hilit; + } else if (*p == '#') { + State = hsMAKE_Comment; + Color = Colors[CLR_Comment]; + goto hilit; + } + } + switch(State) { + case hsMAKE_Comment: + Color = Colors[CLR_Comment]; + goto hilit; + + case hsMAKE_DotCmd: + Color = Colors[CLR_Directive]; + goto hilit; + + case hsMAKE_Command: + Color = Colors[CLR_Command]; + goto hilit; + + default: + State = hsMAKE_Normal; + Color = Colors[CLR_Normal]; + hilit: + ColorNext(); + continue; + } + } + } + if((len1 == 0) || (*last != '\\')) { + if (State == hsMAKE_Comment || State == hsMAKE_DotCmd || State == hsMAKE_Command) + State = hsMAKE_Normal; + } + *ECol = C; + return 0; +} + +#endif diff --git a/src/h_merge.cpp b/src/h_merge.cpp new file mode 100644 index 0000000..9865c5a --- /dev/null +++ b/src/h_merge.cpp @@ -0,0 +1,59 @@ +/* h_merge.cpp + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#include "fte.h" + +#ifdef CONFIG_HILIT_MERGE + +#define hsMERGE_Normal 0 +#define hsMERGE_Modified 1 +#define hsMERGE_Original 2 +#define hsMERGE_New 3 +#define hsMERGE_Control 4 + +int Hilit_MERGE(EBuffer *BF, int /*LN*/, PCell B, int Pos, int Width, ELine* Line, hlState& State, hsState *StateMap, int *ECol) { + ChColor *Colors = BF->Mode->fColorize->Colors; + HILIT_VARS(Colors[CLR_Normal], Line); + hlState StateO = State; + hlState StateN = State; + + if (Line->Count >= 7) { + State = hsMERGE_Control; + if (memcmp(Line->Chars, "<<<<<<<", 7) == 0) + StateN = hsMERGE_Modified; + else if (memcmp(Line->Chars, "|||||||", 7) == 0) + StateN = hsMERGE_Original; + else if (memcmp(Line->Chars, "=======", 7) == 0) + StateN = hsMERGE_New; + else if (memcmp(Line->Chars, ">>>>>>>", 7) == 0) + StateN = hsMERGE_Normal; + else + State = StateO; + } + + for (i = 0; i < Line->Count; ) { + IF_TAB() else { + switch(State) { + case hsMERGE_Control: Color = Colors[CLR_Control]; break; + case hsMERGE_Modified: Color = Colors[CLR_Changed]; break; + case hsMERGE_Original: Color = Colors[CLR_Old]; break; + case hsMERGE_New: Color = Colors[CLR_New]; break; + default: Color = Colors[CLR_Normal]; break; + + } + ColorNext(); + continue; + } + } + State = StateN; + *ECol = C; + return 0; +} + +#endif diff --git a/src/h_msg.cpp b/src/h_msg.cpp new file mode 100644 index 0000000..6d1ff76 --- /dev/null +++ b/src/h_msg.cpp @@ -0,0 +1,150 @@ +/* h_msg.cpp + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#include "fte.h" + +#ifdef CONFIG_HILIT_MSG + +#define hsMSG_Normal 0 +#define hsMSG_Header 1 +#define hsMSG_Quote 2 +#define hsMSG_Tag 3 +#define hsMSG_Control 4 + +int Hilit_MSG(EBuffer *BF, int /*LN*/, PCell B, int Pos, int Width, ELine* Line, hlState& State, hsState *StateMap, int *ECol) { + ChColor *Colors = BF->Mode->fColorize->Colors; + HILIT_VARS(Colors[CLR_Normal], Line); + int is_head = 0, is_quote = 0, is_space = 0, is_tag = 0, is_control = 0; + + if (Line->Count > 0) { + if (State == hsMSG_Header) { + if (Line->Chars[0] == ' ' || Line->Chars[0] == '\t') is_head = 1; + else + State = hsMSG_Normal; + } + if (State == hsMSG_Normal) { + if (Line->Count >= 2 && + Line->Chars[0] == '-' && + Line->Chars[1] == '-' && + (Line->Count == 2 || Line->Chars[2] == ' ')) + is_tag = 1; + else if (Line->Count >= 2 && + Line->Chars[0] == '.' && + Line->Chars[1] == '.' && + (Line->Count == 2 || Line->Chars[2] == ' ')) + is_tag = 1; + else if (Line->Count >= 3 && + Line->Chars[0] == '-' && + Line->Chars[1] == '-' && + Line->Chars[2] == '-' && + (Line->Count == 3 || Line->Chars[3] == ' ')) + is_tag = 1; + else if (Line->Count >= 3 && + Line->Chars[0] == '.' && + Line->Chars[1] == '.' && + Line->Chars[2] == '.' && + (Line->Count == 3 || Line->Chars[3] == ' ')) + is_tag = 1; + else if (Line->Count > 10 && memcmp(Line->Chars, " * Origin:", 10) == 0) + is_control = 1; + else if (Line->Count > 0 && Line->Chars[0] == '\x01') + is_control = 1; + else for (i = 0; i < Line->Count; i++) { + if (i < 30 && Line->Chars[i] == ':' && i < Line->Count - 1 && Line->Chars[i+1] == ' ' && !is_space) { is_head = 1; break; } + else if (i < 5 && Line->Chars[i] == '>') { is_quote = 1; break; } + else if (Line->Chars[i] == '<' || + (Line->Chars[i] == ' ' && i > 0) || + Line->Chars[i] == '\t') break; + else if (Line->Chars[i] == ' ' || Line->Chars[i] == '\t') + is_space = 0; + } + } + } + if (is_head) { + State = hsMSG_Header; + Color = Colors[CLR_Header]; + } else if (is_quote) { + State = hsMSG_Quote; + Color = Colors[CLR_Quotes]; + } else if (is_tag) { + State = hsMSG_Tag; + Color = Colors[CLR_Tag]; + } else if (is_control) { + State = hsMSG_Control; + Color = Colors[CLR_Control]; + } else { + State = hsMSG_Normal; + Color = Colors[CLR_Normal]; + } + + ChColor DefColor = Color; +#ifdef CONFIG_WORD_HILIT + int j = 0; + + if (BF->Mode->fColorize->Keywords.TotalCount > 0 || + BF->WordCount > 0) + { /* words have to be hilited, go slow */ + for(i = 0; i < Line->Count;) { + IF_TAB() else { + if (isalpha(*p) || (*p == '_')) { + j = 0; + while (((i + j) < Line->Count) && + (isalnum(Line->Chars[i+j]) || + (Line->Chars[i + j] == '_')) + ) j++; + if (BF->GetHilitWord(j, Line->Chars + i, Color, 1)) ; + else { + Color = DefColor; + } + if (StateMap) + memset(StateMap + i, State, j); + if (B) + MoveMem(B, C - Pos, Width, Line->Chars + i, Color, j); + i += j; + len -= j; + p += j; + C += j; + Color = DefColor; + continue; + } + ColorNext(); + continue; + } + } + } else +#endif + if (ExpandTabs) { /* use slow mode */ + for (i = 0; i < Line->Count;) { + IF_TAB() else { + ColorNext(); + } + } + } else { /* fast mode */ + if (Pos < Line->Count) { + if (Pos + Width < Line->Count) { + if (B) + MoveMem(B, 0, Width, Line->Chars + Pos, Color, Width); + if (StateMap) + memset(StateMap, State, Line->Count); + } else { + if (B) + MoveMem(B, 0, Width, Line->Chars + Pos, Color, Line->Count - Pos); + if (StateMap) + memset(StateMap, State, Line->Count); + } + } + C = Line->Count; + } + if (State != hsMSG_Header) + State = hsMSG_Normal; + *ECol = C; + return 0; +} + +#endif diff --git a/src/h_pascal.cpp b/src/h_pascal.cpp new file mode 100644 index 0000000..dfff9fa --- /dev/null +++ b/src/h_pascal.cpp @@ -0,0 +1,139 @@ +/* h_pascal.cpp + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#include "fte.h" + +#ifdef CONFIG_HILIT_PASCAL + +#define hsPas_Normal 0 +#define hsPas_Comment1 1 +#define hsPas_Comment2 2 +#define hsPas_Keyword 3 +#define hsPas_String1 4 +#define hsPas_String2 5 + +int Hilit_PASCAL(EBuffer *BF, int /*LN*/, PCell B, int Pos, int Width, ELine *Line, hlState &State, hsState *StateMap, int *ECol) { + ChColor *Colors = BF->Mode->fColorize->Colors; + int j = 0; + int firstnw = 0; + HILIT_VARS(Colors[CLR_Normal], Line); + + C = 0; + NC = 0; + for(i = 0; i < Line->Count;) { + if (*p != ' ' && *p != 9) firstnw++; + IF_TAB() else { + switch(State) { + default: + case hsPas_Normal: + if (isalpha(*p) || *p == '_') { + j = 0; + while (((i + j) < Line->Count) && + (isalnum(Line->Chars[i+j]) || + (Line->Chars[i + j] == '_')) + ) j++; + if (BF->GetHilitWord(j, &Line->Chars[i], Color, 1)) { + // Color = hcC_Keyword; + State = hsPas_Keyword; + } else { + Color = Colors[CLR_Normal]; + State = hsPas_Normal; + } + if (StateMap) + memset(StateMap + i, State, j); + if (B) + MoveMem(B, C - Pos, Width, Line->Chars + i, Color, j); + i += j; + len -= j; + p += j; + C += j; + State = hsPas_Normal; + continue; + } else if ((len >= 2) && (*p == '(') && (*(p+1) == '*')) { + State = hsPas_Comment1; + Color = Colors[CLR_Comment]; + ColorNext(); + goto hilit; + } else if (*p == '{') { + State = hsPas_Comment2; + Color = Colors[CLR_Comment]; + goto hilit; + } else if (*p == '$') { + Color = Colors[CLR_HexNumber]; + ColorNext(); + ColorNext(); + while (len && isxdigit(*p)) ColorNext(); + continue; + } else if (isdigit(*p)) { + Color = Colors[CLR_Number]; + ColorNext(); + while (len && (isdigit(*p) || *p == 'e' || *p == 'E' || *p == '.')) ColorNext(); + continue; + } else if (*p == '\'') { + State = hsPas_String1; + Color = Colors[CLR_String]; + goto hilit; + } else if (*p == '"') { + State = hsPas_String2; + Color = Colors[CLR_String]; + goto hilit; + } else if (ispunct(*p) && *p != '_') { + Color = Colors[CLR_Punctuation]; + goto hilit; + } + Color = Colors[CLR_Normal]; + goto hilit; + case hsPas_Comment1: + Color = Colors[CLR_Comment]; + if ((len >= 2) && (*p == '*') && (*(p+1) == ')')) { + ColorNext(); + ColorNext(); + State = hsPas_Normal; + continue; + } + goto hilit; + case hsPas_Comment2: + Color = Colors[CLR_Comment]; + if (*p == '}') { + ColorNext(); + State = hsPas_Normal; + continue; + } + goto hilit; + case hsPas_String1: + Color = Colors[CLR_String]; + if (*p == '\'') { + ColorNext(); + State = hsPas_Normal; + continue; + } + goto hilit; + case hsPas_String2: + Color = Colors[CLR_String]; + if (*p == '"') { + ColorNext(); + State = hsPas_Normal; + continue; + } + hilit: + ColorNext(); + continue; + } + } + } + switch(State) { + case hsPas_String1: + case hsPas_String2: + State = hsPas_Normal; + break; + } + *ECol = C; + return 0; +} +#endif diff --git a/src/h_perl.cpp b/src/h_perl.cpp new file mode 100644 index 0000000..f773d80 --- /dev/null +++ b/src/h_perl.cpp @@ -0,0 +1,598 @@ +/* h_perl.cpp + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +/* + * Perl Mode + * + * TODO: + * here documents, formats + * OS/2 EXTPROC..., + * UNIX #! starts hilit ? + * POD highlighting (need two keyword sets). + * some tab handling (in & foo, etc -- if allowed)/ + */ + +#include "fte.h" + +#ifdef CONFIG_HILIT_PERL + +#define X_BIT 0x80 /* set if last was number, var, */ +#define X_MASK 0x7F +#define X_NOT(state) (!((state) & X_BIT)) + +#define kwd(x) (isalnum(x) || (x) == '_') + +#define IS_OBRACE(x) \ + ((x) == '(' || (x) == '{' || (x) == '<' || (x) == '[') + +#define NUM_BRACE(x) \ + ( \ + (x) == '(' ? 0U : \ + (x) == '{' ? 1U : \ + (x) == '<' ? 2U : \ + (x) == '[' ? 3U : 0U \ + ) + +#define GET_BRACE(x) \ + ( \ + (x) == 0 ? '(' : \ + (x) == 1 ? '{' : \ + (x) == 2 ? '<' : \ + (x) == 3 ? '[' : 0 \ + ) + +#define IS_MBRACE(y,x) \ + ( \ + ((y) == '(' && (x) == ')') || \ + ((y) == '{' && (x) == '}') ||\ + ((y) == '<' && (x) == '>') ||\ + ((y) == '[' && (x) == ']') \ + ) + +#define QCHAR(state) ((char)(((state) >> 8) & 0xFF)) +#define QSET(state, ch) ((unsigned short)((unsigned short)(state) | (((unsigned short)(ch)) << 8))) + +#define hsPerl_Punct 0 +#define hsPerl_Comment 1 +#define hsPerl_Normal 30 +#define hsPerl_Keyword 4 +#define hsPerl_String1 10 +#define hsPerl_String2 11 +#define hsPerl_StringBk 22 +#define hsPerl_Variable 23 +#define hsPerl_Number 24 +#define hsPerl_Function 25 +#define hsPerl_RegexpM 26 +#define hsPerl_RegexpS1 28 +#define hsPerl_RegexpS2 29 +#define hsPerl_Docs 31 +#define hsPerl_Data 32 +#define hsPerl_RegexpS3 33 + +#define hsPerl_Quote1Op 35 +#define hsPerl_Quote1 36 +#define hsPerl_Quote1M 37 + +#define hsPerl_Regexp1Op 38 +#define hsPerl_Regexp1 39 +#define hsPerl_Regexp1M 40 + +#define hsPerl_Regexp2Op 41 +#define hsPerl_Regexp2 42 +#define hsPerl_Regexp2M 43 + +#define hsPerl_HereDoc 44 // hack (eod not detected properly) + +#define opQ 1 +#define opQQ 2 +#define opQW 3 +#define opQX 4 +#define opM 5 +#define opS 6 +#define opTR 7 + +int Hilit_PERL(EBuffer *BF, int /*LN*/, PCell B, int Pos, int Width, ELine *Line, hlState &State, hsState *StateMap, int *ECol) { + ChColor *Colors = BF->Mode->fColorize->Colors; + int j; + HILIT_VARS(Colors[CLR_Normal], Line); + int firstnw = 0; + int op; + int setHereDoc = 0; +#define MAXSEOF 100 + static char hereDocKey[MAXSEOF]; + + C = 0; + NC = 0; + int isEOHereDoc = 0; + for(i = 0; i < Line->Count;) { + if (*p != ' ' && *p != 9) firstnw++; + if ((State & X_MASK) == hsPerl_HereDoc && 0 == i) + { + isEOHereDoc = strlen(hereDocKey) == (size_t)len && + strncmp(hereDocKey, Line->Chars, len) == 0; + } + IF_TAB() else { + // printf("State = %d pos = %d", State, i); fflush(stdout); + switch (State & X_MASK) { + default: + case hsPerl_Normal: + if (i == 0 && X_NOT(State) && len == 7 && + p[0] == '_' && + p[1] == '_' && + p[2] == 'E' && + p[3] == 'N' && + p[4] == 'D' && + p[5] == '_' && + p[6] == '_') + { + State = hsPerl_Data; + Color = Colors[CLR_Comment]; + hilit5: + ColorNext(); + //hilit4: + ColorNext(); + //hilit3: + ColorNext(); + hilit2: + ColorNext(); + hilit: + ColorNext(); + continue; + } else if (i == 0 && X_NOT(State) && (*p == '=') && len > 4 && + p[1] == 'h' && p[2] == 'e' && p[3] == 'a' && p[4] == 'd') + { + State = hsPerl_Docs; + Color = Colors[CLR_Comment]; + goto hilit5; + } else if (isalpha(*p) || *p == '_') { + op = -1; + + j = 0; + while (((i + j) < Line->Count) && + (isalnum(Line->Chars[i+j]) || + (Line->Chars[i + j] == '_' || Line->Chars[i + j] == '\'')) + ) j++; + if (BF->GetHilitWord(j, &Line->Chars[i], Color)) { + //Color = hcPERL_Keyword; + State = hsPerl_Keyword; + } else { + int x; + x = i + j; + while ((x < Line->Count) && + ((Line->Chars[x] == ' ') || (Line->Chars[x] == 9))) x++; + if ((x < Line->Count) && (Line->Chars[x] == '(')) { + Color = Colors[CLR_Function]; + } else { + Color = Colors[CLR_Normal]; + } + State = hsPerl_Normal; + } + if (j == 1) { + if (*p == 'q') op = opQ; + else if (*p == 's' || *p == 'y') op = opS; + else if (*p == 'm') op = opM; + } else if (j == 2) { + if (*p == 'q') { + if (*p == 'q') op = opQQ; + else if (*p == 'w') op = opQW; + else if (*p == 'x') op = opQX; + } else if (*p == 't' && p[1] == 'r') op = opTR; + } + if (StateMap) + memset(StateMap + i, State, j); + if (B) + MoveMem(B, C - Pos, Width, Line->Chars + i, Color, j); + i += j; + len -= j; + p += j; + C += j; + + switch (op) { + case opQ: + State = hsPerl_Quote1Op; // q{} operator + Color = Colors[CLR_Punctuation]; + continue; + + case opQQ: + case opQW: + case opQX: + State = hsPerl_Quote1Op; // qq{} qx{} qw{} operators + Color = Colors[CLR_Punctuation]; + continue; + + case opM: + State = hsPerl_Regexp1Op; // m{} operator + Color = Colors[CLR_Punctuation]; + continue; + + case opTR: + State = hsPerl_Regexp2Op; // tr{} operators + Color = Colors[CLR_RegexpDelim]; + continue; + + case opS: + State = hsPerl_Regexp2Op; // s{}{} operator + Color = Colors[CLR_Punctuation]; + continue; + + default: + State = hsPerl_Normal; + continue; + } + } else if (len >= 2 && ((*p == '-' && p[1] == '-') || (*p == '+' && p[1] == '+'))) { + hlState s = State; + State = hsPerl_Punct; + Color = Colors[CLR_Punctuation]; + ColorNext(); + ColorNext(); + State = s; + continue; + } else if (len >= 2 && *p == '&' && (p[1] == '&' || isspace(p[1]))) { + State = hsPerl_Punct; + Color = Colors[CLR_Punctuation]; + ColorNext(); + ColorNext(); + State = hsPerl_Normal; + continue; + } else if (*p == '&' && (len < 2 || p[1] != '&') && X_NOT(State)) { + State = hsPerl_Function; + Color = Colors[CLR_Function]; + ColorNext(); + while ((len > 0) && (*p == '$' || + *p == '@' || + *p == '*' || + *p == '%' || + *p == '\\')) + ColorNext(); + while ((len > 0) && (isalnum(*p) || + *p == '_' || + *p == '\'')) + ColorNext(); + State = hsPerl_Normal | X_BIT; + continue; + } else if ((*p == '$') && (len > 1) && + ((p[1] == '$') || p[1] == '"')) { + State = hsPerl_Variable; + Color = Colors[CLR_Variable]; + ColorNext(); + ColorNext(); + State = hsPerl_Normal | X_BIT; + continue; + } else if (*p == '$' || *p == '@' || *p == '\\' || (len > 2 && (*p == '%' || *p == '*') && X_NOT(State))) { + State = hsPerl_Variable; + Color = Colors[CLR_Variable]; + ColorNext(); + while ((len > 0) && ((*p == ' ') || (*p == '\t'))) { + IF_TAB() else + ColorNext(); + } + while ((len > 0) && (*p == '$' || + *p == '@' || + *p == '*' || + *p == '%' || + *p == '\\')) + ColorNext(); + if (len > 0 && *p != '{' && *p != ' ' && *p != '\t' && *p != '"' && *p != '\'') + ColorNext(); + while ((len > 0) && (isalnum(*p) || + *p == '_' || + *p == '\'')) + ColorNext(); + State = hsPerl_Normal | X_BIT; + continue; + } else if ((len >= 2) && (*p == '0') && (*(p+1) == 'x')) { + State = hsPerl_Number; + Color = Colors[CLR_Number]; + ColorNext(); + ColorNext(); + while (len && (isxdigit(*p) || *p == '_')) ColorNext(); + // if (len && (toupper(*p) == 'U')) ColorNext(); + // if (len && (toupper(*p) == 'L')) ColorNext(); + State = hsPerl_Normal | X_BIT; + continue; + } else if (isdigit(*p)) { + State = hsPerl_Number; + Color = Colors[CLR_Number]; + ColorNext(); + while (len && (isdigit(*p) || (*p == 'e' || *p == 'E' || *p == '_'))) ColorNext(); + // if (len && (toupper(*p) == 'U')) ColorNext(); + // if (len && (toupper(*p) == 'L')) ColorNext(); + State = hsPerl_Normal | X_BIT; + continue; + } else if (*p == '\'') { + State = QSET(hsPerl_String1, '\''); + Color = Colors[CLR_String]; + goto hilit; + } else if (*p == '"') { + State = QSET(hsPerl_String2, '"'); + Color = Colors[CLR_String]; + goto hilit; + } else if (*p == '<' && len > 2 && p[1] == '<' && + (p[2] == '"' || p[2] == '\'' || p[2] == '_' || (toupper(p[2]) >= 'A' && toupper(p[2]) <= 'Z'))) + { + int hereDocKeyLen; + setHereDoc++; + for (hereDocKeyLen = 0; + hereDocKeyLen < len && ( + p[2 + hereDocKeyLen] == '_' || + (toupper(p[2 + hereDocKeyLen]) >= 'A' && toupper(p[2 + hereDocKeyLen]) <= 'Z') + ); + ++hereDocKeyLen) + { + hereDocKey[hereDocKeyLen] = p[2 + hereDocKeyLen]; + } + hereDocKey[hereDocKeyLen] = '\0'; + State = hsPerl_Punct; + Color = Colors[CLR_Punctuation]; + ColorNext(); + State = hsPerl_Normal; + continue; + } else if (*p == '`') { + State = QSET(hsPerl_StringBk, '`'); + Color = Colors[CLR_String]; + goto hilit; + } else if (*p == '#') { + State = hsPerl_Comment | (State & X_BIT); + continue; + } else if (X_NOT(State) && *p == '/') { + State = QSET(hsPerl_Regexp1, '/'); + Color = Colors[CLR_RegexpDelim]; + goto hilit; + } else if (X_NOT(State) && + *p == '-' && + len >= 2 && + isalpha(p[1]) + ) { + Color = Colors[CLR_Normal]; // default. + if (strchr("wrxoRWXOezsfdlpSbctugkTB", p[1]) != NULL) { + Color = Colors[CLR_Punctuation]; // new default. + if (len > 2) { + switch(p[2]) { + case '_': // there may be others... + Color = Colors[CLR_Normal]; + break; + default: + if (isalnum(p[2])) + Color = Colors[CLR_Normal]; + break; + } + } + } + ColorNext(); + ColorNext(); + State = hsPerl_Normal; + continue; + } else if (*p == ')' || *p == ']') { + State = hsPerl_Punct; + Color = Colors[CLR_Punctuation]; + ColorNext(); + State = hsPerl_Normal | X_BIT; + continue; + } else if (ispunct(*p)) { + State = hsPerl_Punct; + Color = Colors[CLR_Punctuation]; + ColorNext(); + State = hsPerl_Normal; + continue; + } + Color = Colors[CLR_Normal]; + goto hilit; + case hsPerl_Quote1Op: + if (*p != ' ' && !kwd(*p)) { + if (IS_OBRACE(*p)) + State = QSET(hsPerl_Quote1M, + (1U << 2) | NUM_BRACE(*p)); + else + State = QSET(hsPerl_Quote1, *p); + Color = Colors[CLR_QuoteDelim]; + goto hilit; + } else if (kwd(*p)) { + State = hsPerl_Normal | X_BIT; + continue; + } + Color = Colors[CLR_Punctuation]; + goto hilit; + case hsPerl_Quote1: + Color = Colors[CLR_String]; + if ((len >= 2) && (*p == '\\')) { + goto hilit2; + } else if (*p == QCHAR(State)) { + Color = Colors[CLR_QuoteDelim]; + ColorNext(); + State = hsPerl_Normal | X_BIT; + continue; + } + goto hilit; + case hsPerl_Quote1M: + Color = Colors[CLR_String]; + if ((len >= 2) && (*p == '\\')) { + goto hilit2; + } else if (GET_BRACE(QCHAR(State) & 3) == *p) { + State += 1 << (2 + 8); + goto hilit; + } else if (IS_MBRACE(GET_BRACE(QCHAR(State) & 3), *p)) { + State -= 1 << (2 + 8); + if ((QCHAR(State) >> 2) == 0) { + Color = Colors[CLR_QuoteDelim]; + ColorNext(); + State = hsPerl_Normal | X_BIT; + } else + goto hilit; + continue; + } + goto hilit; + case hsPerl_Regexp1Op: + if (*p != ' ' && !kwd(*p)) { + if (IS_OBRACE(*p)) + State = QSET(hsPerl_Regexp1M, + (1U << 2) | NUM_BRACE(*p)); + else + State = QSET(hsPerl_Regexp1, *p); + Color = Colors[CLR_RegexpDelim]; + goto hilit; + } else if (kwd(*p)) { + State = hsPerl_Normal | X_BIT; + continue; + } + Color = Colors[CLR_Regexp]; + goto hilit; + case hsPerl_Regexp1: + Color = Colors[CLR_Regexp]; + if ((len >= 2) && (*p == '\\')) { + goto hilit2; + } else if (*p == QCHAR(State)) { + Color = Colors[CLR_RegexpDelim]; + ColorNext(); + Color = Colors[CLR_Punctuation]; + while (len > 0 && isalpha(*p)) + ColorNext(); + State = hsPerl_Normal | X_BIT; + continue; + } + goto hilit; + case hsPerl_Regexp1M: + Color = Colors[CLR_Regexp]; + if ((len >= 2) && (*p == '\\')) { + goto hilit2; + } else if (GET_BRACE(QCHAR(State) & 3) == *p) { + State += 1 << (2 + 8); + goto hilit; + } else if (IS_MBRACE(GET_BRACE(QCHAR(State) & 3), *p)) { + State -= 1 << (2 + 8); + if ((QCHAR(State) >> 2) == 0) { + Color = Colors[CLR_RegexpDelim]; + ColorNext(); + Color = Colors[CLR_Punctuation]; + while (len > 0 && isalpha(*p)) + ColorNext(); + State = hsPerl_Normal | X_BIT; + } else + goto hilit; + continue; + } + goto hilit; + case hsPerl_Regexp2Op: + if (*p != ' ' && !kwd(*p)) { + if (IS_OBRACE(*p)) + State = QSET(hsPerl_Regexp2M, + (1U << 2) | NUM_BRACE(*p)); + else + State = QSET(hsPerl_Regexp2, *p); + Color = Colors[CLR_RegexpDelim]; + goto hilit; + } else if (kwd(*p)) { + State = hsPerl_Normal | X_BIT; + continue; + } + Color = Colors[CLR_Regexp]; + goto hilit; + case hsPerl_Regexp2: + Color = Colors[CLR_Regexp]; + if ((len >= 2) && (*p == '\\')) { + goto hilit2; + } else if (*p == QCHAR(State)) { + Color = Colors[CLR_RegexpDelim]; + ColorNext(); + /*State = hsPerl_Normal | X_BIT;*/ + State = QSET(hsPerl_Regexp1, QCHAR(State)); + continue; + } + goto hilit; + case hsPerl_Regexp2M: + Color = Colors[CLR_Regexp]; + if ((len >= 2) && (*p == '\\')) { + goto hilit2; + } else if (GET_BRACE(QCHAR(State) & 3) == *p) { + State += 1 << (2 + 8); + goto hilit; + } else if (IS_MBRACE(GET_BRACE(QCHAR(State) & 3), *p)) { + State -= 1 << (2 + 8); + if ((QCHAR(State) >> 2) == 0) { + Color = Colors[CLR_RegexpDelim]; + ColorNext(); + /*State = hsPerl_Normal | X_BIT;*/ + State = hsPerl_Regexp1Op; + } else + goto hilit; + continue; + } + goto hilit; + case hsPerl_Data: + Color = Colors[CLR_Comment]; + goto hilit; + case hsPerl_HereDoc: + if (!isEOHereDoc) + { + Color = Colors[CLR_String]; + goto hilit; + } + Color = Colors[CLR_Punctuation]; + setHereDoc = QCHAR(State); + while (len > 0) + ColorNext(); + State = hsPerl_Normal | (State & X_BIT); + continue; + case hsPerl_Docs: + Color = Colors[CLR_Comment]; + if (i == 0 && *p == '=' && len > 3 && + p[1] == 'c' && p[2] == 'u' && p[3] == 't') + { + ColorNext(); + ColorNext(); + ColorNext(); + ColorNext(); + State = hsPerl_Normal; + Color = Colors[CLR_Normal]; + continue; + } + goto hilit; + case hsPerl_Comment: + Color = Colors[CLR_Comment]; + goto hilit; + case hsPerl_String1: + Color = Colors[CLR_String]; + if ((len >= 2) && (*p == '\\')) { + goto hilit2; + } else if (*p == QCHAR(State)) { + ColorNext(); + State = hsPerl_Normal | X_BIT; + continue; + } + goto hilit; + case hsPerl_String2: + Color = Colors[CLR_String]; + if ((len >= 2) && (*p == '\\')) { + goto hilit2; + } else if (*p == QCHAR(State)) { + ColorNext(); + State = hsPerl_Normal | X_BIT; + continue; + } + goto hilit; + case hsPerl_StringBk: + Color = Colors[CLR_String]; + if ((len >= 2) && (*p == '\\')) { + goto hilit2; + } else if (*p == QCHAR(State)) { + ColorNext(); + State = hsPerl_Normal | X_BIT; + continue; + } + goto hilit; + } + } + } + if ((State & X_MASK) == hsPerl_Comment) + State = hsPerl_Normal | (State & X_BIT); + if (setHereDoc) + State = QSET(hsPerl_HereDoc | (State & X_BIT), setHereDoc - 1); + *ECol = C; + return 0; +} +#endif diff --git a/src/h_plain.cpp b/src/h_plain.cpp new file mode 100644 index 0000000..ddf9819 --- /dev/null +++ b/src/h_plain.cpp @@ -0,0 +1,95 @@ +/* h_plain.cpp + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#include "fte.h" + +#define hsPLAIN_Normal 0 + +int Hilit_Plain(EBuffer *BF, int /*LN*/, PCell B, int Pos, int Width, ELine* Line, hlState& State, hsState *StateMap, int *ECol) { + ChColor *Colors = BF->Mode->fColorize->Colors; + HILIT_VARS(Colors[CLR_Normal], Line); + +#ifdef CONFIG_WORD_HILIT + int j = 0; + + if (BF->Mode->fColorize->Keywords.TotalCount > 0 || + BF->WordCount > 0) + { /* words have to be hilited, go slow */ + for(i = 0; i < Line->Count;) { + IF_TAB() else { + if (isalpha(*p) || (*p == '_')) { + j = 0; + while (((i + j) < Line->Count) && + (isalnum(Line->Chars[i+j]) || + (Line->Chars[i + j] == '_')) + ) j++; + if (BF->GetHilitWord(j, Line->Chars + i, Color, 1)) ; + else { + Color = Colors[CLR_Normal]; + State = hsPLAIN_Normal; + } + if (StateMap) + memset(StateMap + i, State, j); + if (B) + MoveMem(B, C - Pos, Width, Line->Chars + i, Color, j); + i += j; + len -= j; + p += j; + C += j; + State = hsPLAIN_Normal; + Color = Colors[CLR_Normal]; + continue; + } + ColorNext(); + continue; + } + } + } else +#endif + if (ExpandTabs) { /* use slow mode */ + for (i = 0; i < Line->Count;) { + IF_TAB() else { + ColorNext(); + } + } + } else { /* fast mode */ + if (Pos < Line->Count) { + if (Pos + Width < Line->Count) { + if (B) + MoveMem(B, 0, Width, Line->Chars + Pos, Color, Width); + if (StateMap) + memset(StateMap, State, Line->Count); + } else { + if (B) + MoveMem(B, 0, Width, Line->Chars + Pos, Color, Line->Count - Pos); + if (StateMap) + memset(StateMap, State, Line->Count); + } + } + C = Line->Count; + } + *ECol = C; + State = 0; + return 0; +} + +int Indent_Plain(EBuffer *B, int Line, int PosCursor) { + int OI = B->LineIndented(Line); + B->IndentLine(Line, B->LineIndented(Line - 1)); + if (PosCursor) { + int I = B->LineIndented(Line); + int X = B->CP.Col; + + X = X - OI + I; + if (X < I) X = I; + if (X < 0) X = 0; + B->SetPosR(X, Line); + } + return 1; +} diff --git a/src/h_rexx.cpp b/src/h_rexx.cpp new file mode 100644 index 0000000..fdce147 --- /dev/null +++ b/src/h_rexx.cpp @@ -0,0 +1,391 @@ +/* h_rexx.cpp + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#include "fte.h" + +#ifdef CONFIG_HILIT_REXX + +#define hsREXX_Normal 0 +#define hsREXX_Comment 1 +#define hsREXX_String1 3 +#define hsREXX_String2 4 +#define hsREXX_Keyword 5 + +int Hilit_REXX(EBuffer *BF, int /*LN*/, PCell B, int Pos, int Width, ELine *Line, hlState &State, hsState *StateMap, int *ECol) { + ChColor *Colors = BF->Mode->fColorize->Colors; + int j = 0; + int firstnw = 0; + HILIT_VARS(Colors[CLR_Normal], Line); + int wascall = 0; + + C = 0; + NC = 0; + for(i = 0; i < Line->Count;) { + if (*p != ' ' && *p != 9) firstnw++; + IF_TAB() else { + switch(State) { + case hsREXX_Comment: + Color = Colors[CLR_Comment]; + if ((len >= 2) && (*p == '*') && (*(p+1) == '/')) { + ColorNext(); + set_normal: + ColorNext(); + State = hsREXX_Normal; + continue; + } + goto hilit; + case hsREXX_String1: + Color = Colors[CLR_String]; + if (*p == '\'') { + goto set_normal; + } + goto hilit; + case hsREXX_String2: + Color = Colors[CLR_String]; + if (*p == '"') { + goto set_normal; + } + goto hilit; + default: + case hsREXX_Normal: + if (isalpha(*p) || (*p == '_')) { + + j = 0; + while (((i + j) < Line->Count) && + (isalnum(Line->Chars[i+j]) || + (Line->Chars[i + j] == '_')) + ) j++; + if (wascall) { + State = hsREXX_Normal; + Color = Colors[CLR_Function]; + wascall = 0; + } else { + if (BF->GetHilitWord(j, Line->Chars + i, Color, 1)) + State = hsREXX_Keyword; + else { + int x; + x = i + j; + if ((x < Line->Count) && (Line->Chars[x] == '(')) { + Color = Colors[CLR_Function]; + } else { + Color = Colors[CLR_Normal]; + } + State = hsREXX_Normal; + } + } + if (StateMap) + memset(StateMap + i, State, j); + if (B) + MoveMem(B, C - Pos, Width, Line->Chars + i, Color, j); + if (State == hsREXX_Keyword) + if (strnicmp(Line->Chars + i, "CALL", 4) == 0) + wascall = 1; + i += j; + len -= j; + p += j; + C += j; + State = hsREXX_Normal; + continue; + } else if ((len >= 2) && (*p == '/') && (*(p+1) == '*')) { + State = hsREXX_Comment; + Color = Colors[CLR_Comment]; + //hilit2: + ColorNext(); + hilit: + ColorNext(); + continue; + } else if (isdigit(*p)) { + Color = Colors[CLR_Number]; + ColorNext(); + while(len && isdigit(*p)) ColorNext(); + continue; + } else if (*p == '\'') { + State = hsREXX_String1; + Color = Colors[CLR_String]; + goto hilit; + } else if (*p == '"') { + State = hsREXX_String2; + Color = Colors[CLR_String]; + goto hilit; + } else if (ispunct(*p) && *p != '_') { + Color = Colors[CLR_Punctuation]; + goto hilit; + } + Color = Colors[CLR_Normal]; + goto hilit; + } + } + } + switch (State) { + case hsREXX_String1: + case hsREXX_String2: + State = hsREXX_Normal; + break; + } + *ECol = C; + return 0; +} + +#ifdef CONFIG_INDENT_REXX + +static int Match(int Len, int Pos, hsState *StateMap, const char *Text, const char *String, hsState State) { + int L = strlen(String); + + if (Pos + L <= Len) + if (StateMap == NULL || IsState(StateMap + Pos, State, L)) + if (strnicmp(String, Text + Pos, L) == 0) + return 1; + return 0; +} + +static int SearchMatch(int Count, EBuffer *B, int Row, int Ctx) { + char *P; + int L; + int Pos; + int StateLen; + hsState *StateMap; + int ICount = (Ctx == 2) ? Count : 0; + + Count = (Ctx == 2) ? 0 : Count; + + + while (Row >= 0) { + P = B->RLine(Row)->Chars; + L = B->RLine(Row)->Count; + StateMap = NULL; + if (B->GetMap(Row, &StateLen, &StateMap) == 0) return -1; + Pos = L - 1; + if (L > 0) while (Pos >= 0) { + if (isalpha(P[Pos])) { + if (Match(L, Pos, StateMap, P, "do", hsREXX_Keyword) || + Match(L, Pos, StateMap, P, "select", hsREXX_Keyword )) + { + Count++; + if (Count == 0 && Ctx != 2) { + if (StateMap) + free(StateMap); + return B->LineIndented(Row); + } + } else if (Match(L, Pos, StateMap, P, "end", hsREXX_Keyword)) { + Count--; + } + if (Ctx == 2 && Count == 0) { + if (Match(L, Pos, StateMap, P, "if", hsREXX_Keyword)) { + ICount++; + if (ICount == 0) { + if (StateMap) + free(StateMap); + return B->LineIndented(Row); + } + } else if (Match(L, Pos, StateMap, P, "else", hsREXX_Keyword)) { + ICount--; + } + } + } + Pos--; + } + if (StateMap) free(StateMap); + Row--; + } + return -1; +} + +static int CheckLabel(EBuffer *B, int Line) { + PELine L = B->RLine(Line); + int P = B->CharOffset(L, B->LineIndented(Line)); + int Cnt = 0; + + if (Line > 0 && B->RLine(Line - 1)->StateE != hsREXX_Normal) + return 0; + + while ((P < L->Count) && + (L->Chars[P] == ' ' || L->Chars[P] == 9)) P++; + while (P < L->Count) { + if (Cnt > 0) + if (L->Chars[P] == ':') return 1; + if (!(isalnum(L->Chars[P]) || (L->Chars[P] == '_'))) return 0; + Cnt++; + P++; + } + return 0; +} + +static int SearchBackContext(EBuffer *B, int Row, char &ChFind) { + char *P; + int L; + int Pos; + int Count = -1; + int StateLen; + hsState *StateMap; + int isblank = 0; + + ChFind = '0'; + while (Row >= 0) { + P = B->RLine(Row)->Chars; + L = B->RLine(Row)->Count; + StateMap = NULL; + if (B->GetMap(Row, &StateLen, &StateMap) == 0) return 0; + Pos = L - 1; + if (L > 0) while (Pos >= 0) { + if (CheckLabel(B, Row) == 1) { + Count++; + ChFind = 'p'; + if (Count == 0) { + if (StateMap) + free(StateMap); + return B->LineIndented(Row); + } + } + if (isalpha(P[Pos]) && (Pos == 0 || !isalpha(P[Pos - 1]))) { + if (Match(L, Pos, StateMap, P, "do", hsREXX_Keyword)) { + Count++; + ChFind = 'd'; + //} else if (Match(L, Pos, StateMap, P, "procedure", hsREXX_Keyword)) { + //Count++; + //ChFind = 'p'; + } else if (Match(L, Pos, StateMap, P, "select", hsREXX_Keyword)) { + Count++; + ChFind = 's'; + } else if (Match(L, Pos, StateMap, P, "otherwise", hsREXX_Keyword) && Count == 0) { + //Count++; + ChFind = 'o'; + if (StateMap) + free(StateMap); + return B->LineIndented(Row); + } else if (Match(L, Pos, StateMap, P, "end", hsREXX_Keyword)) { + Count--; + ChFind = 'e'; + } else if (isblank < 5 && Match(L, Pos, StateMap, P, "then", hsREXX_Keyword)) { + ChFind = 't'; + if (StateMap) + free(StateMap); + return B->LineIndented(Row); + } else if (isblank < 5 && Match(L, Pos, StateMap, P, "else", hsREXX_Keyword)) { + ChFind = 'e'; + if (StateMap) + free(StateMap); + return B->LineIndented(Row); + } else { + isblank++; + Pos--; + continue; + } + if (Count == 0) { + if (StateMap) + free(StateMap); + return B->LineIndented(Row); + } + } + if (P[Pos] != ' ' && P[Pos] != 9) isblank++; + Pos--; + } + if (StateMap) free(StateMap); + Row--; + } + return -1; +} + +int REXX_Base_Indent = 4; +int REXX_Do_Offset = 0; + +#define REXX_BASE_INDENT REXX_Base_Indent +#define REXX_DO_OFFSET REXX_Do_Offset + +static int IndentComment(EBuffer *B, int Row, int /*StateLen*/, hsState * /*StateMap*/) { + int I = 0; + + if (Row > 0) { + I = B->LineIndented(Row - 1); + if (B->RLine(Row - 1)->StateE == hsREXX_Comment) + if (LookAt(B, Row - 1, I, "/*", hsREXX_Comment, 0)) I+= 1; + } + return I; +} + + +static int IndentNormal(EBuffer *B, int Line, int /*StateLen*/, hsState * /*StateMap*/) { + int I = 0; + + if (CheckLabel(B, Line)) { + return 0; + } else if (LookAtNoCase(B, Line, 0, "end", hsREXX_Keyword)) { + return SearchMatch(-1, B, Line - 1, 1); + } else if (LookAtNoCase(B, Line, 0, "else", hsREXX_Keyword)) { + return SearchMatch(-1, B, Line - 1, 2); + } else { + char ChFind; + + I = SearchBackContext(B, Line - 1, ChFind); + if (I == -1) + return 0; + switch (ChFind) { + case 'p': + if (LookAtNoCase(B, Line, 0, "return", hsREXX_Keyword)) + return I; + else + return I + REXX_BASE_INDENT; + case 's': + case 'd': + return I + REXX_BASE_INDENT; + case 't': + case 'e': + case 'o': + if (LookAtNoCase(B, Line, 0, "do", hsREXX_Keyword)) + return I + REXX_DO_OFFSET; + else + return I + REXX_BASE_INDENT; + default: + return I; + } + } +} + +int Indent_REXX(EBuffer *B, int Line, int PosCursor) { + int I; + hsState *StateMap = NULL; + int StateLen = 0; + int OI; + + OI = I = B->LineIndented(Line); + if (I != 0) B->IndentLine(Line, 0); + if (B->GetMap(Line, &StateLen, &StateMap) == 0) return 0; + + if (StateLen > 0) { // line is not empty + if (StateMap[0] == hsREXX_Comment) { + I = IndentComment(B, Line, StateLen, StateMap); + } else { + I = IndentNormal(B, Line, StateLen, StateMap); + } + } else { + I = IndentNormal(B, Line, 0, NULL); + } + if (StateMap) + free(StateMap); + if (I >= 0) + B->IndentLine(Line, I); + else + I = 0; + if (PosCursor == 1) { + int X = B->CP.Col; + + X = X - OI + I; + if (X < I) X = I; + if (X < 0) X = 0; + if (X > B->LineLen(Line)) { + X = B->LineLen(Line); + if (X < I) X = I; + } + if (B->SetPosR(X, Line) == 0) return 0; + } else if (PosCursor == 2) { + if (B->SetPosR(I, Line) == 0) return 0; + } + return 1; +} +#endif +#endif diff --git a/src/h_sh.cpp b/src/h_sh.cpp new file mode 100644 index 0000000..8d3cde2 --- /dev/null +++ b/src/h_sh.cpp @@ -0,0 +1,256 @@ +/* h_sh.cpp + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#include "fte.h" + +#ifdef CONFIG_HILIT_SH + +enum { hsSH_Normal, hsSH_SQuote, hsSH_DQuote, hsSH_BQuote, +hsSH_DBQuote, hsSH_Control, hsSH_Keyword, hsSH_Comment, +hsSH_Variable, hsSH_EOF }; + +#define MAXSEOF 100 +static char seof[MAXSEOF]; + +int Hilit_SH(EBuffer *BF, int /*LN*/, PCell B, int Pos, int Width, ELine *Line, hlState &State, hsState *StateMap, int *ECol) { + ChColor *Colors = BF->Mode->fColorize->Colors; + HILIT_VARS(Colors[CLR_Normal], Line); + int CommandStr = 0; + + int isEOF = 0; + for (i = 0; i < Line->Count;) { + if (State == hsSH_EOF && 0 == i) + { + //printf("i=%d, len=%d, strlen(seof)=%d, seof=%s, Line-Chars=%s\n", + // i, len, strlen(seof), seof, Line->Chars); + + // Skip past any leading tabs. + char* iseof = Line->Chars; + size_t len_left = len; + while (*iseof == '\t') ++iseof, --len_left; + + isEOF = strlen(seof) == len_left && + strncmp(seof, iseof, len_left) == 0; + } + IF_TAB() else { + int j = 1; + + if (!isspace(*p)) + CommandStr++; + Color = Colors[CLR_Normal]; + switch (State) { + case hsSH_Normal: + if (CommandStr == 1 && len > 2 && *p == '.' && isspace(p[1])) { + Color = Colors[CLR_Keyword]; + } else if (isalpha(*p) || *p == '_' + || ((CommandStr == 1) + && (*p == '/' || *p == '.'))) { + while (len > j + && (isalnum(p[j]) || strchr("_-[]$", p[j]) != NULL + || ((CommandStr == 1) + && (p[j] == '/' || p[j] == '.')))) + j++; + if (p[j] == '=') + Color = Colors[CLR_Variable]; + else if (p[j] == '*' || p[j] == ')') + Color = Colors[CLR_Normal]; + else { + if (!BF->GetHilitWord(j, p, Color, 0)) { + // Color for good match is set by this function + Color = (CommandStr == 1) ? + Colors[CLR_Command]: + Colors[CLR_Normal]; + //printf("Command %d %c%c\n", + //CommandStr, + //Line->Chars[i],Line->Chars[i+1]); + } else { + if (i > 0 && p[-1] != ';' && p[-1] != '(' + && !isspace(p[-1])) + Color = Colors[CLR_Normal]; + else { + int s; + switch(j) { + case 2: + s = strncmp(p, "in", j); + break; + case 3: + s = strncmp(p, "for", j); + break; + case 4: + s = strncmp(p, "read", j); + break; + case 5: + s = strncmp(p, "unset", j); + break; + case 6: + s = strncmp(p, "export", j); + break; + default: + s = 1; + break; + } + if (s) + CommandStr = 0; + } + } + } + break; + } else if (*p == '[' || *p == ']' || + (CommandStr == 1 && *p == '!')) { + CommandStr = 0; + Color = Colors[CLR_Keyword]; //Colors[CLR_Control]; + //static a=0; + //if (!a) {for(int i=0;i= 2 && *p == '\\' && p[1] == '\'' ) { + Color = Colors[CLR_String]; + ColorNext(); + } else if ( len >= 2 && *p == '\\' && p[1] == '"' ) { + Color = Colors[CLR_String]; + ColorNext(); + } else if (*p == '`') { + State = hsSH_BQuote; + Color = Colors[CLR_Command]; + } else if (*p == '~') { + Color = Colors[CLR_Variable]; + } else if (*p == '$') { + State = hsSH_Variable; + Color = Colors[CLR_Variable]; + } else if (*p == '#') { + State = hsSH_Comment; + Color = Colors[CLR_Comment]; + //} else if (isdigit(*p)) { + //Color = Colors[CLR_Number]; + //while (len > 0 && (isdigit(*p))) + //ColorNext(); + //continue; + } else if (len > 3 && *p == '<' && p[1] == '<') { + + // !!! this is a hack, doesn't work properly -- Mark + + char *s = seof; + + j++; + Color = Colors[CLR_Control]; + while (len > j && isspace(p[j])) + j++; + if( p[j] == '\\' ) j++; + while (len > j && !isspace(p[j])) + *s++ = p[j++]; + *s = 0; + State = hsSH_EOF; + break; + } else if (*p == '=' || *p == '\\' || *p == '>' || + *p == '<' || *p == '!' /*|| *p == ':'*/) { + Color = Colors[CLR_Control]; + } else if (strchr(";|&(){}", *p) != NULL) { + CommandStr = 0; + Color = Colors[CLR_Control]; + } + break; + case hsSH_SQuote: + Color = Colors[CLR_String]; + if ((len >= 2) && (*p == '\\')) + j++; + else if (*p == '\'') + State = hsSH_Normal; + break; + case hsSH_DQuote: + Color = Colors[CLR_String]; + if ((len >= 2) && (*p == '\\')) + j++; + else if (*p == '"') + State = hsSH_Normal; + else if (*p == '`') { + Color = Colors[CLR_Command]; + State = hsSH_DBQuote; + } + break; + case hsSH_BQuote: + Color = Colors[CLR_Command]; + if ((len >= 2) && (*p == '\\')) + j++; + else if (*p == '`') + State = hsSH_Normal; + break; + case hsSH_DBQuote: + Color = Colors[CLR_Command]; + if ((len >= 2) && (*p == '\\')) + j++; + else if (*p == '`') + State = hsSH_DQuote; + break; + case hsSH_Variable: + Color = Colors[CLR_Variable]; + State = hsSH_Normal; + if (!isdigit(*p)) { + int b = 1; + if (*p == '{') + b = 2; + else if (*p == '[') + b = 3; + while (b && len > 0 && + (isalnum(*p) || + (strchr("{}[]_", *p) != NULL) || + (b == 2 && (strchr("#%:-=?+/", *p) != NULL)) || + (b == 1 && (strchr("*@#?-$!", *p) != NULL) /*&& (b = 0, 1) ????? */) + ) + ) + { // !!!!! ????? + if (b == 2 && *p == '}') + b = 0; + else if (b == 3 && *p == ']') + b = 0; + ColorNext(); + } + continue; + } + break; + case hsSH_Comment: + Color = Colors[CLR_Comment]; + break; + case hsSH_EOF: + Color = Colors[CLR_String]; + + if (isEOF) + { + Color = Colors[CLR_Control]; + State = hsSH_Normal; + j += len - 1; + } + break; + default: + State = hsSH_Normal; + Color = Colors[CLR_Normal]; + } + + if (StateMap) + memset(StateMap + i, State, j); + if (B) + MoveMem(B, C - Pos, Width, p, Color, j); + i += j; + len -= j; + p += j; + C += j; + } + } + if (State == hsSH_Comment || State == hsSH_Variable) + State = hsSH_Normal; + *ECol = C; + return 0; +} +#endif diff --git a/src/h_simple.cpp b/src/h_simple.cpp new file mode 100644 index 0000000..b360c97 --- /dev/null +++ b/src/h_simple.cpp @@ -0,0 +1,239 @@ +/* h_simple.cpp + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#include "fte.h" + +#ifdef CONFIG_HILIT_SIMPLE + +int Hilit_SIMPLE(EBuffer *BF, int /*LN*/, PCell B, int Pos, int Width, ELine *Line, hlState &State, hsState *StateMap, int *ECol) { + EColorize *col = BF->Mode->fColorize; + ChColor *Colors = col->Colors; + HMachine *hm = col->hm; + HILIT_VARS(Colors[CLR_Normal], Line); + HState *st = 0; + HTrans *tr = 0; + int t, cc; + int quotech = 0; + int matchFlags; + int matchLen; + int nextState; + char *match; + + if (hm == 0 || col == 0 || hm->stateCount == 0) + return 0; + + if (State >= hm->stateCount) + State = 0; + st = hm->state + State; + Color = Colors[st->color]; + + /*{ + fprintf(stderr, "ColMode:%s, State:%d\n", col->Name, State); + for (int s = 0; s < hm->stateCount; s++) { + fprintf(stderr, + "State:%d, transCount:%d, firstTrans:%d, options:%d, color:%d, nextState:%d\n", + s, + hm->state[s].transCount, + hm->state[s].firstTrans, + hm->state[s].options, + hm->state[s].color, + hm->state[s].nextState); + } + for (int t = 0; t < hm->transCount; t++) { + fprintf(stderr, + "Trans:%d, matchLen:%d, matchFlags:%d, nextState:%d, color:%d\n", + t, + hm->trans[t].matchLen, + hm->trans[t].matchFlags, + hm->trans[t].nextState, + hm->trans[t].color); + } + //exit(1); + sleep(5); + }*/ + + for (i = 0; i < Line->Count; ) { + if (quotech) { + quotech = 0; + } else { + for (t = 0; t < st->transCount; t++) { + tr = hm->trans + st->firstTrans + t; + matchLen = tr->matchLen; + matchFlags = tr->matchFlags; + match = tr->match; + nextState = tr->nextState; + + //fprintf(stderr, + // "line:%d, char:%d, len:%d, state:%d, tr:%d, st->transCount:%d, st->firstTrans, nextState:%d, matchFlags:%d\n", + // LN, i, len, State, t, st->transCount, st->firstTrans, nextState, matchFlags); + + if (len < matchLen) + continue; + + if ((matchFlags & (MATCH_SET | MATCH_NOTSET)) == 0) { + if (matchFlags & MATCH_NO_CASE) { + if (memicmp(match, p, matchLen)) + continue; + } else { + for (cc = 0; cc < matchLen; cc++) + if (p[cc] != match[cc]) + goto next_trans; + } + } else if (matchFlags & MATCH_SET) { + if (!WGETBIT(match, *p)) + continue; + } else if (matchFlags & MATCH_NOTSET) { + if (WGETBIT(match, *p)) + continue; + } + + if ((i > 0) && (matchFlags & MATCH_MUST_BOL)) + continue; + + if ((len != matchLen) && (matchFlags & MATCH_MUST_EOL)) + continue; + + if (matchFlags & MATCH_NOGRAB) { + State = nextState; + if (State >= hm->stateCount) + State = 0; + st = hm->state + State; + //fprintf(stderr, "nograb\n"); + } else { + if (matchFlags & MATCH_TAGASNEXT) { + State = nextState; + if (State >= hm->stateCount) + State = 0; + st = hm->state + State; + } + Color = Colors[tr->color]; + for (cc = 0; cc < matchLen; cc++) + IF_TAB() + else + ColorNext(); + if (!(matchFlags & MATCH_TAGASNEXT)) { + State = nextState; + if (State >= hm->stateCount) + State = 0; + st = hm->state + State; + } + if (len > 0) { + if (matchFlags & MATCH_QUOTECH) + quotech = 1; + } else if (len == 0) { + if (matchFlags & MATCH_QUOTEEOL) + goto end_parse; /* see note below !! */ + } + } + //fprintf(stderr, "next state\n"); + goto next_state; + next_trans: /* */; + } + if (st->wordChars != 0) { + int j; + hlState MState = State; + + j = 0; + while (((i + j) < Line->Count) && + (WGETBIT(st->wordChars, Line->Chars[i + j]))) j++; + + //GP (fix) + Color = Colors[st->color]; + + if (j == 0) { + if (st->nextKwdNoCharState != -1) { + State = st->nextKwdNoCharState; + if (State >= hm->stateCount) + State = 0; + st = hm->state + State; + Color = Colors[st->color]; + goto next_state; + } + } else { + if (st->GetHilitWord(j, &Line->Chars[i], Color ) || + BF->GetHilitWord(j, &Line->Chars[i], Color, BFI( BF, BFI_MatchCase ) ? 0 : 1)) + { + if (st->nextKwdMatchedState != -1) + State = st->nextKwdMatchedState; + } else { + if (st->nextKwdNotMatchedState != -1) { + State = st->nextKwdNotMatchedState; + if (st->options & STATE_NOGRAB) { + if (State >= hm->stateCount) + State = 0; + st = hm->state + State; + Color = Colors[st->color]; + goto next_state; + } + } + } + + if (State >= hm->stateCount) + State = 0; + + // highlight/tag as next state + if (st->options & STATE_TAGASNEXT) { + MState = State; + st = hm->state + State; + Color = Colors[st->color]; + } + + if (StateMap) + memset(StateMap + i, MState, j); + if (B) + MoveMem(B, C - Pos, Width, Line->Chars + i, Color, j); + i += j; + len -= j; + p += j; + C += j; + + if (!(st->options & STATE_TAGASNEXT)) { + st = hm->state + State; + Color = Colors[st->color]; + } + goto next_state; + } + } + } + Color = Colors[st->color]; + IF_TAB() + else + ColorNext(); + next_state: /* */; + } + + /* check if there are any matches for EOL */ + /* NOTE: this is skipped when Q option is used above. !! */ + for (t = 0; t < st->transCount; t++) { + tr = hm->trans + st->firstTrans + t; + matchLen = tr->matchLen; + matchFlags = tr->matchFlags; + match = tr->match; + nextState = tr->nextState; + + if ((i > 0) && (matchFlags & MATCH_MUST_BOL)) + continue; + + //cant match eol beyond eol. + //if ((len != matchLen) && (matchFlags & MATCH_MUST_EOL)) + //continue; + + if (matchLen == 0) { + State = nextState; + if (State >= hm->stateCount) + State = 0; + break; + } + } +end_parse: ; + *ECol = C; + return 0; +} + +#endif diff --git a/src/h_tex.cpp b/src/h_tex.cpp new file mode 100644 index 0000000..dc72179 --- /dev/null +++ b/src/h_tex.cpp @@ -0,0 +1,89 @@ +/* h_tex.cpp + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#include "fte.h" + +#ifdef CONFIG_HILIT_TEX + +#define hsTEX_Normal 0 +#define hsTEX_Tag 1 +#define hsTEX_Comment 2 +#define hsTEX_Special 3 + +int Hilit_TEX(EBuffer *BF, int /*LN*/, PCell B, int Pos, int Width, ELine *Line, hlState &State, hsState *StateMap, int *ECol) { + ChColor *Colors = BF->Mode->fColorize->Colors; + HILIT_VARS(Colors[CLR_Normal], Line); + int j; + + for (i = 0; i < Line->Count;) { + IF_TAB() else { + switch (State) { + case hsTEX_Normal: + Color = Colors[CLR_Normal]; + if (*p == '%') { + State = hsTEX_Comment; + Color = Colors[CLR_Comment]; + goto hilit; + } else if (*p == '\\') { + State = hsTEX_Tag; + Color = Colors[CLR_Tag]; + ColorNext(); + continue; + } else if (*p == '{' || *p == '}' || *p == '$' || *p == '&' || *p == '|') { + State = hsTEX_Special; + Color = Colors[CLR_Special]; + ColorNext(); + State = hsTEX_Normal; + continue; + } + goto hilit; + case hsTEX_Tag: + Color = Colors[CLR_Tag]; + if (isalpha(*p)) { + j = 0; + while (((i + j) < Line->Count) && + (isalnum(Line->Chars[i+j])/* || + (Line->Chars[i + j] == '_')*/) + ) j++; + if (BF->GetHilitWord(j, &Line->Chars[i], Color, 0)) { + } + if (StateMap) + memset(StateMap + i, State, j); + if (B) + MoveMem(B, C - Pos, Width, Line->Chars + i, Color, j); + i += j; + len -= j; + p += j; + C += j; + Color = Colors[CLR_Normal]; + State = hsTEX_Normal; + continue; + } + ColorNext(); + Color = Colors[CLR_Normal]; + State = hsTEX_Normal; + continue; + case hsTEX_Comment: + Color = Colors[CLR_Comment]; + goto hilit; + default: + State = hsTEX_Normal; + Color = Colors[CLR_Normal]; + hilit: + ColorNext(); + continue; + } + } + } + if (State == hsTEX_Comment) + State = hsTEX_Normal; + *ECol = C; + return 0; +} +#endif diff --git a/src/i_ascii.cpp b/src/i_ascii.cpp new file mode 100644 index 0000000..6e6acf7 --- /dev/null +++ b/src/i_ascii.cpp @@ -0,0 +1,129 @@ +/* i_ascii.cpp + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#include "fte.h" + +#ifdef CONFIG_I_ASCII + +static int SPos = 0; +static int SLPos = 0; + +ExASCII::ExASCII(): ExView() { + Pos = SPos; + LPos = SLPos; +} + +ExASCII::~ExASCII() { + SPos = Pos; + SLPos = LPos; +} + +void ExASCII::Activate(int gotfocus) { + ExView::Activate(gotfocus); +} + +int ExASCII::BeginMacro() { + return 1; +} + +void ExASCII::HandleEvent(TEvent &Event) { + int W, H; + + ConQuerySize(&W, &H); + + switch (Event.What) { + case evKeyDown: + switch(kbCode(Event.Key.Code)) { + case kbLeft: Pos--; Event.What = evNone; break; + case kbRight: Pos++; Event.What = evNone; break; + case kbHome: Pos = 0; Event.What = evNone; break; + case kbEnd: Pos = 255; Event.What = evNone; break; + case kbLeft + kfCtrl: Pos -= 16; Event.What = evNone; break; + case kbRight + kfCtrl: Pos += 16; Event.What = evNone; break; + case kbUp: Pos -= W; LPos -= W; Event.What = evNone; break; + case kbDown: Pos += W; LPos += W; Event.What = evNone; break; + case kbEsc: EndExec(-1); Event.What = evNone; break; + case kbEnter: EndExec(Pos); Event.What = evNone; break; + } + break; +#if 0 + case evMouseDown: + if (E.Mouse.X < XPos || E.Mouse.X >= XPos + 34 || + E.Mouse.Y < YPos || E.Mouse.Y >= YPos + 10) + { + abort = 2; + break; + } + + do { + x = E.Mouse.X - XPos - 1; + y = E.Mouse.Y - YPos - 1; + if (x >= 0 && x < 32 && + y >= 0 && y < 8) + { + X = x; + Y = y; + if (X >= 32) X = 31; + if (Y >= 8) Y = 7; + if (X < 0) X = 0; + if (Y < 0) Y = 0; + frames->ConSetCursorPos(X + XPos + 1, Y + YPos + 1); + sprintf(s, "0%03o %03d 0x%02X", + X + Y * 32, X + Y * 32, X + Y * 32); + MoveStr(B, 0, 13, s, hcAsciiStatus, 13); + frames->ConPutBox(XPos + 2, YPos + 9, 13, 1, B); + } + if (E.Mouse.Count == 2) { + abort = 1; + break; + } + gui->ConGetEvent(evMouse, &E, -1, 1); + if (E.What == evMouseUp) break; + } while (1); + break; +#endif + } +} + +void ExASCII::UpdateView() { + if (Next) { + Next->UpdateView(); + } +} + +void ExASCII::RepaintView() { + if (Next) { + Next->RepaintView(); + } +} + +void ExASCII::UpdateStatus() { + RepaintStatus(); +} + +void ExASCII::RepaintStatus() { + TDrawBuffer B; + int W, H; + + ConQuerySize(&W, &H); + + if (Pos > 255) Pos = 255; + if (Pos < 0) Pos = 0; + if (LPos + W < Pos) LPos = Pos - W + 1; + if (LPos > 255 - W) LPos = 255 - W + 1; + if (LPos > Pos) LPos = Pos; + if (LPos < 0) LPos = 0; + + for (int i = 0; i < W; i++) + MoveCh(B + i, char(i + LPos), hcAsciiChars, 1); + ConSetCursorPos(Pos - LPos, H - 1); + ConShowCursor(); + ConPutBox(0, H - 1, W, 1, B); +} +#endif diff --git a/src/i_ascii.h b/src/i_ascii.h new file mode 100644 index 0000000..774c473 --- /dev/null +++ b/src/i_ascii.h @@ -0,0 +1,30 @@ +/* i_ascii.h + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#ifndef __EXASCII_H +#define __EXASCII_H + +class ExASCII: public ExView { +public: + int Pos, LPos; + + ExASCII(); + virtual ~ExASCII(); + virtual void Activate(int gotfocus); + + virtual ExView* GetViewContext() { return Next; } + virtual int BeginMacro(); + virtual void HandleEvent(TEvent &Event); + virtual void UpdateView(); + virtual void RepaintView(); + virtual void UpdateStatus(); + virtual void RepaintStatus(); +}; + +#endif diff --git a/src/i_choice.cpp b/src/i_choice.cpp new file mode 100644 index 0000000..2abefb1 --- /dev/null +++ b/src/i_choice.cpp @@ -0,0 +1,186 @@ +/* i_choice.cpp + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#include "fte.h" + +ExChoice::ExChoice(const char *ATitle, int NSel, va_list ap): ExView() { + char msg[1024]; + int i; + char *fmt; + + Cur = 0; + MouseCaptured = 0; + + Title = strdup(ATitle); + lTitle = strlen(Title); + NOpt = NSel; + lChoice = 0; + + for (i = 0; i < NSel; i++) { + SOpt[i] = strdup(va_arg(ap, char *)); + lChoice += CStrLen(SOpt[i]) + 1; + } + fmt = va_arg(ap, char *); + vsprintf(msg, fmt, ap); + strncpy(Prompt, msg, sizeof(Prompt)); + Prompt[sizeof(Prompt) - 1] = 0; +} + +ExChoice::~ExChoice() { + free(Title); + for (int i = 0; i < NOpt; i++) + free(SOpt[i]); +} + +void ExChoice::Activate(int gotfocus) { + ExView::Activate(gotfocus); +} + +int ExChoice::BeginMacro() { + return 1; +} + +int ExChoice::FindChoiceByPoint(int x, int y) { + int pos, i; + int W, H; + + Win->ConQuerySize(&W, &H); + + if (y != H - 1) + return -1; + + pos = W - lChoice; + if (x < pos) + return -1; + + for (i = 0; i < NOpt; i++) { + int clen = CStrLen(SOpt[i]); + + if (x > pos && x <= pos + clen) + return i; + pos += clen + 1; + } + return -1; +} + +void ExChoice::HandleEvent(TEvent &Event) { + int i; + + switch (Event.What) { + case evKeyDown: + switch (kbCode(Event.Key.Code)) { + case kbTab | kfShift: + case kbLeft: if (Cur == -1) Cur = 0; Cur--; if (Cur < 0) Cur = NOpt - 1; Event.What = evNone; break; + case kbTab: + case kbRight: if (Cur == -1) Cur = 0; Cur++; if (Cur >= NOpt) Cur = 0; Event.What = evNone; break; + case kbHome: Cur = 0; Event.What = evNone; break; + case kbEnd: Cur = NOpt - 1; Event.What = evNone; break; + case kbEnter: if (Cur >= 0 && NOpt > 0) EndExec(Cur); Event.What = evNone; break; + case kbEsc: EndExec(-1); Event.What = evNone; break; + default: + if (isAscii(Event.Key.Code)) { + char c = char(Event.Key.Code & 0xFF); + char s[3]; + + s[0] = '&'; + s[1] = (char)(toupper((char)c) & 0xFF); + s[2] = 0; + + for (i = 0; i < NOpt; i++) { + if (strstr(SOpt[i], s) != 0) { + Win->EndExec(i); + break; + } + } + Event.What = evNone; + } + break; + } + break; + case evMouseDown: + if (Win->CaptureMouse(1)) + MouseCaptured = 1; + else + break; + Cur = FindChoiceByPoint(Event.Mouse.X, Event.Mouse.Y); + Event.What = evNone; + break; + case evMouseMove: + if (MouseCaptured) + Cur = FindChoiceByPoint(Event.Mouse.X, Event.Mouse.Y); + Event.What = evNone; + break; + case evMouseUp: + if (MouseCaptured) + Win->CaptureMouse(0); + else + break; + MouseCaptured = 0; + Cur = FindChoiceByPoint(Event.Mouse.X, Event.Mouse.Y); + Event.What = evNone; + if (Cur >= 0 && Cur < NOpt && NOpt > 0) + EndExec(Cur); + else + Cur = 0; + break; + } +} + +void ExChoice::UpdateView() { + if (Next) { + Next->UpdateView(); + } +} + +void ExChoice::RepaintView() { + if (Next) { + Next->RepaintView(); + } +} + +void ExChoice::UpdateStatus() { + RepaintStatus(); +} + +void ExChoice::RepaintStatus() { + TDrawBuffer B; + int W, H; + int pos, i; + TAttr color1, color2; + + ConQuerySize(&W, &H); + + + if (Cur != -1) { + if (Cur >= NOpt) Cur = NOpt - 1; + if (Cur < 0) Cur = 0; + } + + MoveCh(B, ' ', hcChoice_Background, W); + MoveStr(B, 0, W, Title, hcChoice_Title, W); + MoveChar(B, lTitle, W, ':', hcChoice_Background, 1); + MoveStr(B, lTitle + 2, W, Prompt, hcChoice_Param, W); + + pos = W - lChoice; + for (i = 0; i < NOpt; i++) { + if (i == Cur) { + color1 = hcChoice_ActiveItem; + color2 = hcChoice_ActiveChar; + } else { + color1 = hcChoice_NormalItem; + color2 = hcChoice_NormalChar; + } + if (i == Cur) + ConSetCursorPos(pos + 1, H - 1); + MoveChar(B, pos, W, ConGetDrawChar(DCH_V), hcChoice_Background, 1); + MoveCStr(B, pos + 1, W, SOpt[i], color1, color2, W); + pos += CStrLen(SOpt[i]) + 1; + } + ConPutBox(0, H - 1, W, 1, B); +} diff --git a/src/i_choice.h b/src/i_choice.h new file mode 100644 index 0000000..fb2ff8d --- /dev/null +++ b/src/i_choice.h @@ -0,0 +1,38 @@ +/* i_choice.h + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#ifndef __EXCHOICE_H +#define __EXCHOICE_H + +class ExChoice: public ExView { +public: + char *Title; + char Prompt[160]; + int NOpt; + char *SOpt[10]; + int Cur; + int lTitle; + int lChoice; + int MouseCaptured; + + ExChoice(const char *ATitle, int NSel, va_list ap /* choices, format, args */); + virtual ~ExChoice(); + virtual void Activate(int gotfocus); + + virtual ExView* GetViewContext() { return Next; } + virtual int BeginMacro(); + int FindChoiceByPoint(int x, int y); + virtual void HandleEvent(TEvent &Event); + virtual void UpdateView(); + virtual void RepaintView(); + virtual void UpdateStatus(); + virtual void RepaintStatus(); +}; + +#endif diff --git a/src/i_complete.cpp b/src/i_complete.cpp new file mode 100644 index 0000000..6496a69 --- /dev/null +++ b/src/i_complete.cpp @@ -0,0 +1,413 @@ +/* i_complete.cpp + * + * Copyright (c) 1998, Zdenek Kabelac + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#include "fte.h" + +#ifdef CONFIG_I_COMPLETE + +#define STRCOMPLETE "Complete Word: [" +#define STRNOCOMPLETE "No word for completition..." + +#define LOCALE_SORT + +#ifdef LOCALE_SORT + +#if defined(__IBMCPP__) +static int _LNK_CONV CmpStr(const void *p1, const void *p2) { +#else +static int CmpStr(const void *p1, const void *p2) { +#endif + //printf("%s %s %d\n", *(char **)p1, *(char **)p2, + // strcoll(*(char **)p1, *(char **)p2)); + return strcoll(*(char **)p1, *(char **)p2); +} +#endif + +/** + * Create Sorted list of possible word extensions + */ +ExComplete::ExComplete(EBuffer *B): ExView() +{ + Buffer = B; + Orig = Buffer->CP; + WordBegin = NULL; + WordFixed = WordPos = WordsLast = 0; + Words = new char *[MAXCOMPLETEWORDS + 2]; + if (Words != NULL) + RefreshComplete(); +} + +ExComplete::~ExComplete() +{ +// fprintf(stderr, "W %p %p %p %d\n", Words, WordContinue, WordBegin, WordsLast); + + if (WordBegin != NULL) + delete WordBegin; + + if (Words != NULL) { + for(int i = 0; i < WordsLast; i++) + delete Words[i]; + delete Words; + } +} + +void ExComplete::Activate(int gotfocus) +{ + ExView::Activate(gotfocus); +} + +int ExComplete::BeginMacro() +{ + return 1; +} + +void ExComplete::HandleEvent(TEvent &Event) +{ + unsigned long kb = kbCode(Event.Key.Code); + int DoQuit = 0; + int i = 0; + + if (WordsLast < 2) { + if ((WordsLast == 1) && (kb != kbEsc)) { + DoQuit = 1; + } else { + EndExec(0); + Event.What = evNone; + } + } else if (Event.What == evKeyDown) { + switch(kb) { + case kbPgUp: + case kbLeft: + // if there would not be locale sort, we could check only + // the next string, but with `locale sort` this is impossible!! + // this loop is little inefficient but it's quite short & nice + for (i = WordPos; i-- > 0;) + if (strncmp(Words[WordPos], Words[i], WordFixed) == 0) { + WordPos = i; + break; + } + Event.What = evNone; + break; + case kbPgDn: + case kbRight: + for(i = WordPos; i++ < WordsLast - 1;) + if (strncmp(Words[WordPos], Words[i], WordFixed) == 0) { + WordPos = i; + break; + } + Event.What = evNone; + break; + case kbHome: + for (i = 0; i < WordPos; i++) + if (strncmp(Words[WordPos], Words[i], WordFixed) == 0) + WordPos = i; + Event.What = evNone; + break; + case kbEnd: + for (i = WordsLast - 1; i > WordPos; i--) + if (strncmp(Words[WordPos], Words[i], WordFixed) == 0) + WordPos = i; + Event.What = evNone; + break; + case kbTab: + while (WordPos < WordsLast - 1) { + WordPos++; + if (strncmp(Words[WordPos], Words[WordPos - 1], + WordFixed + 1)) + break; + } + Event.What = evNone; + break; + case kbTab | kfShift: + while (WordPos > 0) { + WordPos--; + if (strncmp(Words[WordPos], Words[WordPos + 1], + WordFixed + 1)) + break; + } + Event.What = evNone; + break; + case kbIns: + case kbUp: + FixedUpdate(1); + Event.What = evNone; + break; + case kbBackSp: + case kbDel: + case kbDown: + FixedUpdate(-1); + Event.What = evNone; + break; + case kbEsc: + EndExec(0); + Event.What = evNone; + break; + case kbEnter: + case kbSpace: + case kbTab | kfCtrl: + DoQuit = 1; + break; + default: + if (CheckASCII(Event.Key.Code)) { + char *s = new char[WordFixed + 2]; + if (s != NULL) { + if (WordFixed > 0) + strncpy(s, Words[WordPos], WordFixed); + s[WordFixed] = (unsigned char)(Event.Key.Code & 0xFF); + s[WordFixed + 1] = 0; + for (int i = 0; i < WordsLast; i++) + if (strncmp(s, Words[i], WordFixed + 1) == 0) { + WordPos = i; + if (WordFixedCount == 1) + DoQuit = 1; + else + FixedUpdate(1); + break; + } + delete s; + } + Event.What = evNone; + } + break; + } + } + + if (DoQuit) { + int rc = 0; + int l = strlen(Words[WordPos]); + + if (Buffer->InsText(Buffer->VToR(Orig.Row), Orig.Col, l, Words[WordPos], 1) + && Buffer->SetPos(Orig.Col + l, Orig.Row)) { + Buffer->Draw(Buffer->VToR(Orig.Row), Buffer->VToR(Orig.Row)); + rc = 1; + } + EndExec(rc); + Event.What = evNone; + } + +} + +void ExComplete::UpdateView() +{ + if (Next) { + Next->UpdateView(); + } +} + +void ExComplete::RepaintView() +{ + if (Next) { + Next->RepaintView(); + } +} + +void ExComplete::UpdateStatus() +{ + RepaintStatus(); +} + +void ExComplete::RepaintStatus() +{ + TDrawBuffer B; + int W, H; + + // Currently use this fixed colors - maybe there are some better defines?? +#define COM_NORM 0x17 +#define COM_ORIG 0x1C +#define COM_HIGH 0x1E +#define COM_MARK 0x2E +#define COM_ERR 0x1C + + ConQuerySize(&W, &H); + MoveCh(B, ' ', COM_NORM, W); + + if ((WordsLast > 0) && (WordBegin != NULL) && (Words != NULL) + && (Words[WordPos]) != NULL) { + const char *sc = STRCOMPLETE; + int p = sizeof(STRCOMPLETE) - 1; + if (W < 35) { + // if the width is quite small + sc += p - 1; // jump to last character + p = 1; + } + MoveStr(B, 0, W, sc, COM_NORM, W); + // int cur = p; + MoveStr(B, p, W, WordBegin, COM_ORIG, W); + p += strlen(WordBegin); + int l = strlen(Words[WordPos]); + if (WordFixed > 0) { + MoveStr(B, p, W, Words[WordPos], COM_MARK, W); + p += WordFixed; + l -= WordFixed; + } + MoveStr(B, p, W, Words[WordPos] + WordFixed, + (WordFixedCount == 1) ? COM_ORIG : COM_HIGH, W); + p += l; + char s[100]; + sprintf(s, "] (T:%d/%d S:%d)", WordPos + 1, WordsLast, + WordFixedCount); + MoveStr(B, p, W, s, COM_NORM, W); + // ConSetCursorPos(cur + WordFixed, H - 1); + } else + MoveStr(B, 0, W, STRNOCOMPLETE, COM_ERR, W); + ConPutBox(0, H - 1, W, 1, B); + ConShowCursor(); +} + +int ExComplete::RefreshComplete() +{ + if ((Buffer->CP.Col == 0) + || (Buffer->SetPos(Buffer->CP.Col, Buffer->CP.Row) == 0)) + return 0; + + PELine L = Buffer->VLine(Buffer->CP.Row); + int C = Buffer->CP.Col; + int P = Buffer->CharOffset(L, C); + + if (!P || P > L->Count) + return 0; + + int P1 = P; + while ((P > 0) && CheckASCII(L->Chars[P - 1])) + P--; + + int wlen = P1 - P; + if (!wlen) + return 0; + + WordBegin = new char[wlen + 1]; + if (WordBegin == NULL) + return 0; + + strncpy(WordBegin, L->Chars + P, wlen); + WordBegin[wlen] = 0; + + // fprintf(stderr, "Calling %d %s\n", wlen, WordBegin); + // Search words in TAGS + TagComplete(Words, &WordsLast, MAXCOMPLETEWORDS, WordBegin); + // fprintf(stderr, "Located %d words\n", WordsLast); + // these words are already sorted + + // Search words in current TEXT + Buffer->Match.Col = Buffer->Match.Row = 0; + // this might look strange but it is necessary to catch + // the first word at position 0,0 for match :-) + unsigned long mask = SEARCH_NOPOS | SEARCH_WORDBEG; + + while (Buffer->FindStr(L->Chars + P, wlen, mask) == 1) { + mask |= SEARCH_NEXT; + PELine M = Buffer->RLine(Buffer->Match.Row); + int X = Buffer->CharOffset(M, Buffer->Match.Col); + + if ((L->Chars == M->Chars) && (P == X)) + continue; + + int XL = X; + + while ((XL < M->Count) && CheckASCII(M->Chars[XL])) + XL++; + + int len = XL - X - wlen; + + if (len == 0) + continue; + + char *s = new char[len + 1]; + + if (s != NULL) { + strncpy(s, M->Chars + X + wlen, len); + s[len] = 0; + + int c = 1, H = 0, L = 0, R = WordsLast; + + // using sort to insert only unique words + while (L < R) { + H = (L + R) / 2; + c = strcmp(s, Words[H]); + if (c < 0) + R = H; + else if (c > 0) + L = H + 1; + else + break; + } + + if (c != 0) { + // Loop exited without finding the word. Instead, + // it found the spot where the new should be inserted. + WordsLast++; + + int i = WordsLast; + + while (i > L) { + Words[i] = Words[i-1]; + i--; + } + + Words[i] = s; + + if (WordsLast >= MAXCOMPLETEWORDS) + break; + } else + { + // word was already listed, free duplicate. + delete s; + } + } + } + Buffer->Match.Row = Buffer->Match.Col = -1; + Buffer->MatchLen = Buffer->MatchCount = 0; + +#ifdef LOCALE_SORT + // sort by current locales + qsort(Words, WordsLast, sizeof(Words[0]), CmpStr); +#endif + + FixedUpdate(0); + + //for(int i = 0; i < WordsLast; i++) + //if (Words[i]) + //fprintf(stderr, "%3d:\t%10p\t%s\n", i, Words[i], Words[i]); + //fprintf(stderr, "Words %3d\n", WordsLast); + + return WordsLast; +} + +void ExComplete::FixedUpdate(int add) +{ + if (add < 0) { + if (WordFixed > 0) + WordFixed += add; + } else if (add > 0) { + if (strlen(Words[WordPos]) > WordFixed) + WordFixed += add; + } + + if (WordFixed > 0) { + WordFixedCount = 0; + for(int i = 0; i < WordsLast; i++) + if (strncmp(Words[WordPos], Words[i], WordFixed) == 0) + WordFixedCount++; + } else + WordFixedCount = WordsLast; + +} +/* + // Well this was my first idea - but these menus are unusable + int menu = NewMenu("CW"); + int n; + n = NewItem(menu, "Word1"); + Menus[menu].Items[n].Cmd = ExFind; + n = NewItem(menu, "Word2"); + Menus[menu].Items[n].Cmd = ExMoveLineStart; + n = NewItem(menu, "Word3"); + Menus[menu].Items[n].Cmd = ExMovePageEnd; + printf(">%d ****\n", View->MView->Win->Parent->PopupMenu("CW")); + */ +#endif diff --git a/src/i_complete.h b/src/i_complete.h new file mode 100644 index 0000000..53c40a9 --- /dev/null +++ b/src/i_complete.h @@ -0,0 +1,47 @@ +/* i_ascii.h + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#ifndef __EXCOMPLETE_H +#define __EXCOMPLETE_H + +// maximum words which will be presented to the user +#define MAXCOMPLETEWORDS 300 + +class ExComplete: public ExView { + EPoint Orig; + EBuffer *Buffer; + int WordsLast; + char **Words; + char *WordBegin; + char *WordContinue; + int WordPos; + size_t WordFixed; + size_t WordFixedCount; + + int RefreshComplete(); + inline int CheckASCII(int c) { + return ((c < 256) + && (isalnum(c) || (c == '_') || (c == '.'))) ? 1 : 0; + } + void FixedUpdate(int add); + +public: + + ExComplete(EBuffer *B); + virtual ~ExComplete(); + virtual void Activate(int gotfocus); + virtual ExView* GetViewContext() { return Next; } + virtual int BeginMacro(); + virtual void HandleEvent(TEvent &Event); + virtual void UpdateView(); + virtual void RepaintView(); + virtual void UpdateStatus(); + virtual void RepaintStatus(); +}; +#endif diff --git a/src/i_input.cpp b/src/i_input.cpp new file mode 100644 index 0000000..132aec9 --- /dev/null +++ b/src/i_input.cpp @@ -0,0 +1,305 @@ +/* i_input.cpp + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#include "fte.h" + +ExInput::ExInput(const char *APrompt, char *ALine, unsigned int ABufLen, Completer AComp, int Select, int AHistId): ExView() { + assert(ABufLen > 0); + MaxLen = ABufLen - 1; + Comp = AComp; + SelStart = SelEnd = 0; + Prompt = strdup(APrompt); + Line = (char *) malloc(MaxLen + 1); + MatchStr = (char *) malloc(MaxLen + 1); + CurStr = (char *) malloc(MaxLen + 1); + if (Line) { + Line[MaxLen] = 0; + strncpy(Line, ALine, MaxLen); + Pos = strlen(Line); + LPos = 0; + } + if (Select) + SelEnd = Pos; + TabCount = 0; + HistId = AHistId; + CurItem = 0; +} + +ExInput::~ExInput() { + if (Prompt) + free(Prompt); + if (Line) + free(Line); + if (MatchStr) + free(MatchStr); + if (CurStr) + free(CurStr); + Prompt = 0; + Line = 0; +} + +void ExInput::Activate(int gotfocus) { + ExView::Activate(gotfocus); +} + +int ExInput::BeginMacro() { + return 1; +} + +void ExInput::HandleEvent(TEvent &Event) { + switch (Event.What) { + case evKeyDown: + switch (kbCode(Event.Key.Code)) { + case kbLeft: if (Pos > 0) Pos--; SelStart = SelEnd = 0; TabCount = 0; Event.What = evNone; break; + case kbRight: Pos++; SelStart = SelEnd = 0; TabCount = 0; Event.What = evNone; break; + case kbLeft | kfCtrl: + if (Pos > 0) { + Pos--; + while (Pos > 0) { + if (isalnum(Line[Pos]) && !isalnum(Line[Pos - 1])) + break; + Pos--; + } + } + SelStart = SelEnd = 0; + TabCount = 0; + Event.What = evNone; + break; + case kbRight | kfCtrl: + { + unsigned int len = strlen(Line); + if (Pos < len) { + Pos++; + while (Pos < len) { + if (isalnum(Line[Pos]) && !isalnum(Line[Pos - 1])) + break; + Pos++; + } + } + } + SelStart = SelEnd = 0; + TabCount = 0; + Event.What = evNone; + break; + case kbHome: Pos = 0; SelStart = SelEnd = 0; TabCount = 0; Event.What = evNone; break; + case kbEnd: Pos = strlen(Line); SelStart = SelEnd = 0; TabCount = 0; Event.What = evNone; break; + case kbEsc: EndExec(0); Event.What = evNone; break; + case kbEnter: +#ifdef CONFIG_HISTORY + AddInputHistory(HistId, Line); +#endif + EndExec(1); + Event.What = evNone; + break; + case kbBackSp | kfCtrl | kfShift: + SelStart = SelEnd = 0; + Pos = 0; + Line[0] = 0; + TabCount = 0; + break; + case kbBackSp | kfCtrl: + if (Pos > 0) { + if (Pos > strlen(Line)) { + Pos = strlen(Line); + } else { + char Ch; + + if (Pos > 0) do { + Pos--; + memmove(Line + Pos, Line + Pos + 1, strlen(Line + Pos + 1) + 1); + if (Pos == 0) break; + Ch = Line[Pos - 1]; + } while (Pos > 0 && Ch != '\\' && Ch != '/' && Ch != '.' && isalnum(Ch)); + } + } + SelStart = SelEnd = 0; + TabCount = 0; + Event.What = evNone; + break; + case kbBackSp: + case kbBackSp | kfShift: + if (SelStart < SelEnd) { + memmove(Line + SelStart, Line + SelEnd, strlen(Line + SelEnd) + 1); + Pos = SelStart; + SelStart = SelEnd = 0; + break; + } + if (Pos <= 0) break; + Pos--; + if (Pos < strlen(Line)) + memmove(Line + Pos, Line + Pos + 1, strlen(Line + Pos + 1) + 1); + TabCount = 0; + Event.What = evNone; + break; + case kbDel: + if (SelStart < SelEnd) { + memmove(Line + SelStart, Line + SelEnd, strlen(Line + SelEnd) + 1); + Pos = SelStart; + SelStart = SelEnd = 0; + break; + } + if (Pos < strlen(Line)) + memmove(Line + Pos, Line + Pos + 1, strlen(Line + Pos + 1) + 1); + TabCount = 0; + Event.What = evNone; + break; + case kbDel | kfCtrl: + if (SelStart < SelEnd) { + memmove(Line + SelStart, Line + SelEnd, strlen(Line + SelEnd) + 1); + Pos = SelStart; + SelStart = SelEnd = 0; + break; + } + SelStart = SelEnd = 0; + Line[Pos] = 0; + TabCount = 0; + Event.What = evNone; + break; + case kbIns | kfShift: + case 'V' | kfCtrl: + { + int len; + + if (SystemClipboard) + GetPMClip(); + + if (SSBuffer == 0) break; + if (SSBuffer->RCount == 0) break; + + if (SelStart < SelEnd) { + memmove(Line + SelStart, Line + SelEnd, strlen(Line + SelEnd) + 1); + Pos = SelStart; + SelStart = SelEnd = 0; + } + + len = SSBuffer->LineChars(0); + if (strlen(Line) + len < MaxLen) { + memmove(Line + Pos + len, Line + Pos, strlen(Line + Pos) + 1); + memcpy(Line + Pos, SSBuffer->RLine(0)->Chars, len); + TabCount = 0; + Event.What = evNone; + Pos += len; + } + } + break; +#ifdef CONFIG_HISTORY + case kbUp: + SelStart = SelEnd = 0; + if (CurItem == 0) + strcpy(CurStr, Line); + CurItem += 2; + case kbDown: + SelStart = SelEnd = 0; + if (CurItem == 0) break; + CurItem--; + { + int cnt = CountInputHistory(HistId); + + if (CurItem > cnt) CurItem = cnt; + if (CurItem < 0) CurItem = 0; + + if (CurItem == 0) + strcpy(Line, CurStr); + else if (GetInputHistory(HistId, Line, MaxLen, CurItem)); + else strcpy(Line, CurStr); + Pos = strlen(Line); +// SelStart = SelEnd = 0; + } + Event.What = evNone; + break; +#endif + case kbTab | kfShift: + TabCount -= 2; + case kbTab: + if (Comp) { + char *Str2 = (char *) malloc(MaxLen + 1); + int n; + + assert(Str2); + TabCount++; + if (TabCount < 1) TabCount = 1; + if ((TabCount == 1) && (kbCode(Event.Key.Code) == kbTab)) { + strcpy(MatchStr, Line); + } + n = Comp(MatchStr, Str2, TabCount); + if ((n > 0) && (TabCount <= n)) { + strcpy(Line, Str2); + Pos = strlen(Line); + } else if (TabCount > n) TabCount = n; + free(Str2); + } + SelStart = SelEnd = 0; + Event.What = evNone; + break; + case 'Q' | kfCtrl: + Event.What = evKeyDown; + Event.Key.Code = Win->GetChar(0); + default: + { + char Ch; + + if (GetCharFromEvent(Event, &Ch) && (strlen(Line) < MaxLen)) { + if (SelStart < SelEnd) { + memmove(Line + SelStart, Line + SelEnd, strlen(Line + SelEnd) + 1); + Pos = SelStart; + SelStart = SelEnd = 0; + } + memmove(Line + Pos + 1, Line + Pos, strlen(Line + Pos) + 1); + Line[Pos++] = Ch; + TabCount = 0; + Event.What = evNone; + } + } + break; + } + Event.What = evNone; + break; + } +} + +void ExInput::UpdateView() { + if (Next) { + Next->UpdateView(); + } +} + +void ExInput::RepaintView() { + if (Next) { + Next->RepaintView(); + } +} + +void ExInput::UpdateStatus() { + RepaintStatus(); +} + +void ExInput::RepaintStatus() { + TDrawBuffer B; + int W, H, FLen, FPos; + + ConQuerySize(&W, &H); + + FPos = strlen(Prompt) + 2; + FLen = W - FPos; + + if (Pos > strlen(Line)) + Pos = strlen(Line); + //if (Pos < 0) Pos = 0; + if (LPos + FLen <= Pos) LPos = Pos - FLen + 1; + if (Pos < LPos) LPos = Pos; + + MoveChar(B, 0, W, ' ', hcEntry_Field, W); + MoveStr(B, 0, W, Prompt, hcEntry_Prompt, FPos); + MoveChar(B, FPos - 2, W, ':', hcEntry_Prompt, 1); + MoveStr(B, FPos, W, Line + LPos, hcEntry_Field, FLen); + MoveAttr(B, FPos + SelStart - LPos, W, hcEntry_Selection, SelEnd - SelStart); + ConSetCursorPos(FPos + Pos - LPos, H - 1); + ConPutBox(0, H - 1, W, 1, B); + ConShowCursor(); +} diff --git a/src/i_input.h b/src/i_input.h new file mode 100644 index 0000000..781499c --- /dev/null +++ b/src/i_input.h @@ -0,0 +1,44 @@ +/* i_input.h + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#ifndef __EXINPUT_H +#define __EXINPUT_H + +typedef int (*Completer)(const char *Name, char *Completed, int Num); + +class ExInput: public ExView { +public: + char *Prompt; + char *Line; + char *MatchStr; + char *CurStr; + unsigned int Pos; + unsigned int LPos; + unsigned int MaxLen; + Completer Comp; + int TabCount; + int HistId; + int CurItem; + unsigned int SelStart; + unsigned int SelEnd; + + ExInput(const char *APrompt, char *ALine, unsigned int AMaxLen, Completer AComp, int Select, int AHistId); + virtual ~ExInput(); + virtual void Activate(int gotfocus); + + virtual ExView *GetViewContext() { return Next; } + virtual int BeginMacro(); + virtual void HandleEvent(TEvent &Event); + virtual void UpdateView(); + virtual void RepaintView(); + virtual void UpdateStatus(); + virtual void RepaintStatus(); +}; + +#endif diff --git a/src/i_key.cpp b/src/i_key.cpp new file mode 100644 index 0000000..54f8efc --- /dev/null +++ b/src/i_key.cpp @@ -0,0 +1,66 @@ +/* i_key.cpp + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#include "fte.h" + +ExKey::ExKey(const char *APrompt): ExView() { + if (APrompt) + Prompt = strdup(APrompt); + else + Prompt = 0; +} + +ExKey::~ExKey() { + free(Prompt); +} + +void ExKey::Activate(int gotfocus) { + ExView::Activate(gotfocus); +} + +int ExKey::BeginMacro() { + return 1; +} + +void ExKey::HandleEvent(TEvent &Event) { + switch (Event.What) { + case evKeyDown: + Key = Event.Key.Code; + if (!(Key & kfModifier)) // not ctrl,alt,shift, .... + EndExec(1); + Event.What = evNone; + break; + } +} + +void ExKey::UpdateView() { + if (Next) { + Next->UpdateView(); + } +} + +void ExKey::RepaintView() { + if (Next) { + Next->RepaintView(); + } +} + +void ExKey::UpdateStatus() { + RepaintStatus(); +} + +void ExKey::RepaintStatus() { + TDrawBuffer B; + int W, H; + + ConQuerySize(&W, &H); + + MoveCh(B, ' ', 0x17, W); + ConPutBox(0, H - 1, W, 1, B); +} diff --git a/src/i_key.h b/src/i_key.h new file mode 100644 index 0000000..ba7e6b9 --- /dev/null +++ b/src/i_key.h @@ -0,0 +1,32 @@ +/* i_key.h + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#ifndef __EXKEY_H +#define __EXKEY_H + +class ExKey: public ExView { +public: + char *Prompt; + TKeyCode Key; + char ch; + + ExKey(const char *APrompt); + virtual ~ExKey(); + virtual void Activate(int gotfocus); + + virtual ExView* GetViewContext() { return Next; } + virtual int BeginMacro(); + virtual void HandleEvent(TEvent &Event); + virtual void UpdateView(); + virtual void RepaintView(); + virtual void UpdateStatus(); + virtual void RepaintStatus(); +}; + +#endif diff --git a/src/i_modelview.cpp b/src/i_modelview.cpp new file mode 100644 index 0000000..b446d78 --- /dev/null +++ b/src/i_modelview.cpp @@ -0,0 +1,75 @@ +/* i_modelview.cpp + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#include "fte.h" + +ExModelView::ExModelView(EView *AView): ExView() { + View = AView; + View->MView = this; + MouseCaptured = 0; + MouseMoved = 0; +} + +ExModelView::~ExModelView() { + if (View) { // close it + delete View; + View = 0; + } +} + +int ExModelView::GetContext() { + return View->GetContext(); +} + +void ExModelView::Activate(int gotfocus) { + ExView::Activate(gotfocus); + View->Activate(gotfocus); +} + +EEventMap *ExModelView::GetEventMap() { + return View->GetEventMap(); +} + +int ExModelView::ExecCommand(int Command, ExState &State) { + return View->ExecCommand(Command, State); +} + +int ExModelView::BeginMacro() { + return View->BeginMacro(); +} + +void ExModelView::HandleEvent(TEvent &Event) { + ExView::HandleEvent(Event); + View->HandleEvent(Event); +} + +void ExModelView::UpdateView() { + View->UpdateView(); +} + +void ExModelView::RepaintView() { + View->RepaintView(); +} + +void ExModelView::RepaintStatus() { + View->RepaintStatus(); +} + +void ExModelView::UpdateStatus() { + View->UpdateStatus(); +} + +void ExModelView::Resize(int width, int height) { + View->Resize(width, height); +} + +void ExModelView::WnSwitchBuffer(EModel *B) { + if (View) + View->SwitchToModel(B); +} diff --git a/src/i_modelview.h b/src/i_modelview.h new file mode 100644 index 0000000..4f703b9 --- /dev/null +++ b/src/i_modelview.h @@ -0,0 +1,40 @@ +/* i_modelview.h + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#ifndef __EXEDIT_H +#define __EXEDIT_H + +class EView; + +class ExModelView: public ExView { +public: + EView *View; + int MouseCaptured; + int MouseMoved; + + ExModelView(EView *AView); + virtual ~ExModelView(); + virtual void Activate(int gotfocus); + + virtual EEventMap *GetEventMap(); + virtual int ExecCommand(int Command, ExState &State); + + virtual int GetContext(); + virtual int BeginMacro(); + virtual void HandleEvent(TEvent &Event); + virtual void UpdateView(); + virtual void RepaintView(); + virtual void UpdateStatus(); + virtual void RepaintStatus(); + virtual void Resize(int width, int height); + virtual void WnSwitchBuffer(EModel *M); + virtual int IsModelView() { return 1; } +}; + +#endif diff --git a/src/i_oview.cpp b/src/i_oview.cpp new file mode 100644 index 0000000..8a53eee --- /dev/null +++ b/src/i_oview.cpp @@ -0,0 +1,106 @@ +/* i_oview.cpp + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#include "fte.h" + +ExView::ExView() { +} + +ExView::~ExView() { +} + +void ExView::Activate(int /*gotfocus*/) { +} + +int ExView::IsActive() { + if (Win) + return Win->IsActive(); + return 0; +} + +EEventMap *ExView::GetEventMap() { return 0; } + +int ExView::ExecCommand(int /*Command*/, ExState &/*State*/) { return ErFAIL; } + +int ExView::BeginMacro() { + return 1; +} + +void ExView::HandleEvent(TEvent &Event) { + if (Event.What == evKeyDown && kbCode(Event.Key.Code) == kbF12) + Win->Parent->SelectNext(0); +} + +void ExView::EndExec(int NewResult) { + if (Win->Result == -2) { // hack + Win->EndExec(NewResult); + } else { + if (Next) { + delete Win->PopView(); // self + } + } +} + +void ExView::UpdateView() { +} + +void ExView::UpdateStatus() { +} + +void ExView::RepaintView() { +} + +void ExView::RepaintStatus() { +} + +void ExView::Resize(int /*width*/, int /*height*/) { + Repaint(); +} + +int ExView::ConPutBox(int X, int Y, int W, int H, PCell Cell) { + if (Win) + return Win->ConPutBox(X, Y, W, H, Cell); + return -1; +} + +int ExView::ConScroll(int Way, int X, int Y, int W, int H, TAttr Fill, int Count) { + if (Win) + return Win->ConScroll(Way, X, Y, W, H, Fill, Count); + return -1; +} + +int ExView::ConQuerySize(int *X, int *Y) { + if (Win) + return Win->ConQuerySize(X, Y); + return -1; +} + +int ExView::ConSetCursorPos(int X, int Y) { + if (Win) + return Win->ConSetCursorPos(X, Y); + return -1; +} + +int ExView::ConShowCursor() { + if (Win) + return Win->ConShowCursor(); + return -1; +} + +int ExView::ConHideCursor() { + if (Win) + return Win->ConHideCursor(); + return -1; +} + +int ExView::ConSetCursorSize(int Start, int End) { + if (Win) + return Win->ConSetCursorSize(Start, End); + return -1; +} diff --git a/src/i_oview.h b/src/i_oview.h new file mode 100644 index 0000000..e697b32 --- /dev/null +++ b/src/i_oview.h @@ -0,0 +1,57 @@ +/* i_oview.h + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#ifndef __IOVIEW_H +#define __IOVIEW_H + +class GxView; +class EBuffer; +class EWindow; + +class ExView { +public: + GxView *Win; + ExView *Next; + + ExView(); + virtual ~ExView(); + + virtual EEventMap *GetEventMap(); + virtual int ExecCommand(int Command, ExState &State); + + virtual void Activate(int gotfocus); + virtual int GetContext() { return CONTEXT_NONE; } + virtual ExView *GetViewContext() { return this; } + virtual ExView *GetStatusContext() { return this; } + virtual int BeginMacro(); + virtual void HandleEvent(TEvent &Event); + virtual void UpdateView(); + virtual void UpdateStatus(); + virtual void RepaintView(); + virtual void RepaintStatus(); + virtual void Resize(int width, int height); + virtual void EndExec(int NewResult); + int IsActive(); + + void Repaint() { RepaintStatus(); RepaintView(); } + void Update() { UpdateStatus(); UpdateView(); } + + int ConPutBox(int X, int Y, int W, int H, PCell Cell); + int ConScroll(int Way, int X, int Y, int W, int H, TAttr Fill, int Count); + int ConQuerySize(int *X, int *Y); + int ConSetCursorPos(int X, int Y); + int ConShowCursor(); + int ConHideCursor(); + int ConSetCursorSize(int Start, int End); + + virtual int IsModelView() { return 0; } + virtual void WnSwitchBuffer(EModel *M) { Next->WnSwitchBuffer(M); } +}; + +#endif diff --git a/src/i_search.cpp b/src/i_search.cpp new file mode 100644 index 0000000..5257d5d --- /dev/null +++ b/src/i_search.cpp @@ -0,0 +1,188 @@ +/* i_search.cpp + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#include "fte.h" + +#ifdef CONFIG_I_SEARCH + +static char PrevISearch[MAXISEARCH] = ""; + +ExISearch::ExISearch(EBuffer *B) { + Buffer = B; + strcpy(ISearchStr, ""); + len = 0; + stacklen = 0; + Orig = Buffer->CP; // ? + Direction = 0; + state = INoMatch; +} + +ExISearch::~ExISearch() { + if (ISearchStr[0] != 0) + strcpy(PrevISearch, ISearchStr); +} + +void ExISearch::Activate(int gotfocus) { + ExView::Activate(gotfocus); +} + +int ExISearch::BeginMacro() { return 1; } + +void ExISearch::HandleEvent(TEvent &Event) { + int Case = BFI(Buffer, BFI_MatchCase) ? 0 : SEARCH_NCASE; + + ExView::HandleEvent(Event); + switch (Event.What) { + case evKeyDown: + SetState(IOk); + switch (kbCode(Event.Key.Code)) { + case kbEsc: + Buffer->SetPos(Orig.Col, Orig.Row); + EndExec(0); + break; + case kbEnter: EndExec(1); break; + case kbBackSp: + if (len > 0) { + if (stacklen > 0) { + stacklen--; + if (Buffer->CenterPos(stack[stacklen].Col, stack[stacklen].Row) == 0) return; + } + len--; + ISearchStr[len] = 0; + if (len > 0 && Buffer->FindStr(ISearchStr, len, Case | Direction) == 0) { + SetState(INoMatch); + } + } else { + if (Buffer->CenterPos(Orig.Col, Orig.Row) == 0) return; + } + break; + case kbUp: + Buffer->ScrollDown(1); + break; + case kbDown: + Buffer->ScrollUp(1); + break; + case kbLeft: + Buffer->ScrollRight(8); + break; + case kbRight: + Buffer->ScrollLeft(8); + break; + case kbPgDn: + Buffer->MovePageDown(); + break; + case kbPgUp: + Buffer->MovePageUp(); + break; + case kbPgUp | kfCtrl: + Buffer->MoveFileStart(); + break; + case kbPgDn | kfCtrl: + Buffer->MoveFileEnd(); + break; + case kbHome: + Buffer->MoveLineStart(); + break; + case kbEnd: + Buffer->MoveLineEnd(); + break; + case kbTab | kfShift: + Direction = SEARCH_BACK; + if (len == 0) { + strcpy(ISearchStr, PrevISearch); + len = strlen(ISearchStr); + if (len == 0) + break; + } + if (Buffer->FindStr(ISearchStr, len, Case | Direction | SEARCH_NEXT) == 0) { + Buffer->FindStr(ISearchStr, len, Case); + SetState(INoPrev); + } + break; + case kbTab: + Direction = 0; + if (len == 0) { + strcpy(ISearchStr, PrevISearch); + len = strlen(ISearchStr); + if (len == 0) + break; + } + if (Buffer->FindStr(ISearchStr, len, Case | Direction | SEARCH_NEXT) == 0) { + Buffer->FindStr(ISearchStr, len, Case); + SetState(INoNext); + } + break; + case 'Q' | kfCtrl: + Event.What = evKeyDown; + Event.Key.Code = Win->GetChar(0); + default: + if (isAscii(Event.Key.Code) && (len < MAXISEARCH)) { + char Ch = (char) Event.Key.Code; + + stack[stacklen] = Buffer->CP; + ISearchStr[len++] = Ch; + ISearchStr[len] = 0; + if (Buffer->FindStr(ISearchStr, len, Case | Direction) == 0) { + SetState(INoMatch); + len--; + stacklen--; + ISearchStr[len] = 0; + Buffer->FindStr(ISearchStr, len, Case | Direction); + } else { + } + } + break; + } + } +} + +void ExISearch::UpdateView() { + if (Next) { + Next->UpdateView(); + } +} + +void ExISearch::RepaintView() { + if (Next) { + Next->RepaintView(); + } +} + +void ExISearch::UpdateStatus() { + RepaintStatus(); +} + +void ExISearch::RepaintStatus() { + TDrawBuffer B; + char s[MAXISEARCH + 1]; + const char *p; + int W, H; + + ConQuerySize(&W, &H); + + switch (state) { + case INoMatch: p = " No Match. "; break; + case INoPrev: p = " No Prev Match. "; break; + case INoNext: p = " No Next Match. "; break; + case IOk: default: p = ""; break; + } + + sprintf(s, "ISearch [%s]%s", ISearchStr, p); + MoveCh(B, ' ', 0x17, W); + MoveStr(B, 0, W, s, 0x17, W); + ConPutBox(0, H - 1, W, 1, B); + ConSetCursorPos(strlen(s) - 1, H - 1); + ConShowCursor(); +} + +void ExISearch::SetState(IState s) { + state = s; + RepaintView(); +} +#endif diff --git a/src/i_search.h b/src/i_search.h new file mode 100644 index 0000000..2ebc3b0 --- /dev/null +++ b/src/i_search.h @@ -0,0 +1,43 @@ +/* i_search.h + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#ifndef __ISEARCH_H +#define __ISEARCH_H + +#define MAXISEARCH 256 + +class ExISearch: public ExView { +public: + typedef enum { IOk, INoMatch, INoPrev, INoNext } IState; + + char ISearchStr[MAXISEARCH + 1]; + EPoint Orig; + EPoint stack[MAXISEARCH]; + int len; + int stacklen; + EBuffer *Buffer; + IState state; + int Direction; + + ExISearch(EBuffer *B); + virtual ~ExISearch(); + virtual void Activate(int gotfocus); + + virtual ExView *GetViewContext() { return Next; } + virtual int BeginMacro(); + virtual void HandleEvent(TEvent &Event); + virtual void UpdateView(); + virtual void RepaintView(); + virtual void UpdateStatus(); + virtual void RepaintStatus(); + + void SetState(IState state); +}; + +#endif diff --git a/src/i_view.cpp b/src/i_view.cpp new file mode 100644 index 0000000..7555f0d --- /dev/null +++ b/src/i_view.cpp @@ -0,0 +1,338 @@ +/* i_view.cpp + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#include "fte.h" + +GxView::GxView(GFrame *Parent): GView(Parent, -1, -1) { + Top = Bottom = 0; + MouseCaptured = 0; +} + +GxView::~GxView() { + if (Top) { + ExView *V; + + while (Top) { + V = Top; + Top = Top->Next; + V->Win = 0; + delete V; + } + } +} + +void GxView::PushView(ExView *view) { + int W, H; + ConQuerySize(&W, &H); + + view->Win = this; + if (Top == 0) { + Top = Bottom = view; + view->Next = 0; + } else { + Top->Activate(0); + view->Next = Top; + Top = view; + Top->Activate(1); + } + Top->Resize(W, H); +} + +ExView *GxView::PopView() { + ExView *V; + + if (Top == 0) + return 0; + + Top->Activate(0); + + V = Top; + Top = Top->Next; + + if (Top == 0) + Bottom = 0; + else { + Top->Activate(1); + Top->Repaint(); + } + V->Win = 0; + + return V; +} + +void GxView::NewView(ExView * /*view*/) { +} + +EEventMap *GxView::GetEventMap() { + if (Top) + return Top->GetEventMap(); + return 0; +} + +int GxView::ExecCommand(int Command, ExState &State) { + if (Top) + return Top->ExecCommand(Command, State); + return 0; +} + +int GxView::BeginMacro() { + if (Top) + return Top->BeginMacro(); + return 1; +} + +int GxView::GetContext() { + if (Top) + return Top->GetContext(); + else + return CONTEXT_NONE; +} + +void GxView::HandleEvent(TEvent &Event) { + GView::HandleEvent(Event); + Top->HandleEvent(Event); + + if (Event.What & evMouse) { + int W, H; + + ConQuerySize(&W, &H); + + if (Event.What != evMouseDown || Event.Mouse.Y == H - 1) { + switch (Event.What) { + case evMouseDown: + if (CaptureMouse(1)) + MouseCaptured = 1; + else + break; + Event.What = evNone; + break; + case evMouseMove: + if (MouseCaptured) { + if (Event.Mouse.Y != H - 1) + ExpandHeight(Event.Mouse.Y - H + 1); + Event.What = evNone; + } + break; + case evMouseAuto: + if (MouseCaptured) + Event.What = evNone; + break; + case evMouseUp: + if (MouseCaptured) + CaptureMouse(0); + else + break; + MouseCaptured = 0; + Event.What = evNone; + break; + } + return ; + } + } +} + +void GxView::Update() { + if (Top) { + Top->Update(); + }// else + // Repaint(); +} + +void GxView::Repaint() { + if (Top) { + Top->Repaint(); + } else { + TDrawBuffer B; + int X, Y; + + ConQuerySize(&X, &Y); + MoveCh(B, ' ', 0x07, X); + ConPutLine(0, 0, X, Y, B); + } +} + +void GxView::Resize(int width, int height) { + ExView *V; + GView::Resize(width, height); + V = Top; + + while (V) { + V->Resize(width, height); + V = V->Next; + } +} + +void GxView::Activate(int gotfocus) { + if (Top) + Top->Activate(gotfocus); + GView::Activate(gotfocus); +} + +void GxView::UpdateTitle(char *Title, char *STitle) { + if (Parent && Parent->Active == this) { + Parent->ConSetTitle(Title, STitle); + } +} + +int GxView::GetStr(const char *Prompt, unsigned int BufLen, char *Str, int HistId) { + if ((HaveGUIDialogs & GUIDLG_PROMPT) && GUIDialogs) { + return DLGGetStr(this, Prompt, BufLen, Str, HistId, 0); + } else { + return ReadStr(Prompt, BufLen, Str, 0, 1, HistId); + } +} + +int GxView::GetFile(const char *Prompt, unsigned int BufLen, char *Str, int HistId, int Flags) { + if ((HaveGUIDialogs & GUIDLG_FILE) && GUIDialogs) + return DLGGetFile(this, Prompt, BufLen, Str, Flags); + else + return ReadStr(Prompt, BufLen, Str, CompletePath, SelectPathname, HistId); +} + +int GxView::ReadStr(const char *Prompt, unsigned int BufLen, char *Str, Completer Comp, int Select, int HistId) { + int rc; + ExInput *input; + + input = new ExInput(Prompt, Str, BufLen, Comp, Select, HistId); + if (input == 0) + return 0; + + PushView((ExView *)input); + + rc = Execute(); + + PopView(); + + Repaint(); + + if (rc == 1) { + strncpy(Str, input->Line, BufLen - 1); + Str[BufLen - 1] = 0; + } + delete input; + + return rc; +} + +int GxView::Choice(unsigned long Flags, const char *Title, int NSel, ... /* choices, format, args */) { + int rc; + va_list ap; + + if ((HaveGUIDialogs & GUIDLG_CHOICE) && GUIDialogs) { + va_start(ap, NSel); + rc = DLGPickChoice(this, Title, NSel, ap, Flags); + va_end(ap); + return rc; + } else { + ExChoice *choice; + + va_start(ap, NSel); + + choice = new ExChoice(Title, NSel, ap); + + va_end(ap); + + if (choice == 0) + return 0; + + PushView(choice); + rc = Execute(); + PopView(); + Repaint(); + + delete choice; + + return rc; + } +} + +TKeyCode GxView::GetChar(const char *Prompt) { + int rc; + ExKey *key; + TKeyCode K = 0; + + key = new ExKey(Prompt); + if (key == 0) + return 0; + + PushView(key); + rc = Execute(); + PopView(); + Repaint(); + + if (rc == 1) + K = key->Key; + delete key; + + return K; +} + +#ifdef CONFIG_I_SEARCH +int GxView::IncrementalSearch(EView *View) { + int rc; + ExISearch *search; + EBuffer *B = 0; + + if (View->GetContext() != CONTEXT_FILE) + return 0; + + B = (EBuffer *)View->Model; + + search = new ExISearch(B); + + if (search == 0) + return 0; + + PushView(search); + rc = Execute(); + PopView(); + Repaint(); + + delete search; + + return rc; +} +#endif + +#ifdef CONFIG_I_ASCII +int GxView::PickASCII() { + int rc; + ExASCII *ascii; + + ascii = new ExASCII(); + if (ascii == 0) + return 0; + + PushView(ascii); + rc = Execute(); + PopView(); + Repaint(); + + delete ascii; + return rc; +} +#endif + +#ifdef CONFIG_I_COMPLETE +int GxView::ICompleteWord(EView *View) { + int rc = 0; + + if (View->GetContext() == CONTEXT_FILE) { + ExComplete *c = new ExComplete((EBuffer *)View->Model); + if (c != NULL) { + PushView(c); + rc = Execute(); + PopView(); + Repaint(); + delete c; + } + } + return rc; +} +#endif diff --git a/src/i_view.h b/src/i_view.h new file mode 100644 index 0000000..bdb7a7f --- /dev/null +++ b/src/i_view.h @@ -0,0 +1,57 @@ +/* i_view.h + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +class EView; + +class GxView: public GView { +public: + ExView *Top; + ExView *Bottom; + int MouseCaptured; + + GxView(GFrame *Parent); + virtual ~GxView(); + + void PushView(ExView *view); + ExView *PopView(); + void NewView(ExView *view); + + EEventMap *GetEventMap(); + int ExecCommand(int Command, ExState &State); + + virtual int GetContext(); + virtual ExView* GetStatusContext() { if (Top) return Top->GetStatusContext(); else return 0; } + virtual ExView* GetViewContext() { if (Top) return Top->GetViewContext(); else return 0; } + virtual int BeginMacro(); + virtual void HandleEvent(TEvent &Event); + virtual void Update(); + virtual void Repaint(); + virtual void Activate(int gotfocus); + virtual void Resize(int width, int height); + + void UpdateTitle(char *Title, char *STitle); + + int ReadStr(const char *Prompt, unsigned int BufLen, char *Str, Completer Comp, int Select, int HistId); + int Choice(unsigned long Flags, const char *Title, int NSel, ... /* choices, format, args */); + TKeyCode GetChar(const char *Prompt); +#ifdef CONFIG_I_SEARCH + int IncrementalSearch(EView *V); +#endif +#ifdef CONFIG_I_ASCII + int PickASCII(); +#endif +#ifdef CONFIG_I_COMPLETE + int ICompleteWord(EView *View); +#endif + + int GetStr(const char *Prompt, unsigned int BufLen, char *Str, int HistId); + int GetFile(const char *Prompt, unsigned int BufLen, char *Str, int HistId, int Flags); + + int IsModelView() { return Top ? Top->IsModelView() : 0; } +}; diff --git a/src/icons/ftepm.ico b/src/icons/ftepm.ico new file mode 100644 index 0000000000000000000000000000000000000000..ce1ba493b868a9aedbc5ee03bcbb0c4fa9c8aa27 GIT binary patch literal 3344 zcmeHJv2NQi5WUnY9Hau0!BZD!^q4=en`$Z0p`VbkW5;Z9CXfA{04*8;4&X%};UYuF zW(-in*Y}R3BvN)7Brdv?#?#}yJKm9$MEUg1NJP#7wzuzI<9dYOa!({j|5zrnhaZ}% zw)`)G{}|qk{;6SVG=()~tEx(&D@K#R%%gg0b?>0DxxD+bFH59i-6K>^>(YPrGWd_4 zQTHPklu6Ik9mqhIKJQ3Abn4Q7w(shWWb}->Tx(PJKn`U3%H& z+DRj_OSAu9cC!QF5CJdyNC_@eK6LsVx19cz%b_0^cx?8<$IVjq`DYz=b!PThscz<5 zug?RoWXyTZ?>c;8Iu{5(&&-WHcKRF?#rK_!71rK0b7v^YL0|DmIr%S_5-wOPqgFBe!!h`T*d~-5M9|fs2dR`>@tb#^M^&dQZ}_ zqC3{FG0Nw(;yuslP}elhzx4_HgH}dkgWCOL`v_Kx&7LrP}be$vl%7- zJBI3==>3W4FEDZc$?+HTiK`RQYcO!_@wJaW#?1gSaS1S2x8<$<3|}EeMg7)aokkBI iI2Rr1bRLine(Line - 1)->StateE == 0) { + Pos = B->LineIndented(Line - 1); + } else { // for comments, strings, etc, use same as prev line. + Pos = B->LineIndented(Line - 1); + } + } + + Old = B->LineIndented(Line); + if (Pos < 0) + Pos = 0; + if (Pos != Old) + if (B->IndentLine(Line, Pos) == 0) + return 0;; + return 1; +} +#endif diff --git a/src/log.cpp b/src/log.cpp new file mode 100644 index 0000000..34f1cce --- /dev/null +++ b/src/log.cpp @@ -0,0 +1,170 @@ +/******************************************************************** + +The author, Darin McBride, explicitly places this module under the +LGPL license. This module must remain free for use, but will not +cause software that uses it to be required to be under the GPL or +any of its derivitives. + +********************************************************************/ + +#include +#include +#include "sysdep.h" +#include "log.h" + +#if defined(NO_NEW_CPP_FEATURES) +#include +#include +#else +#include +#include + +using namespace std; +#endif + +#ifndef FTE_NO_LOGGING + +/********************************************************************* + * + * Required variables: + * + *********************************************************************/ + +GlobalLog globalLog; + +bool GlobalLog::OpenLogFile() +{ + if (!m_bOpened && m_strLogFile != NULL) + { + m_ofsLog.open(m_strLogFile, ios::out /*| ios::text*/ | ios::app /*append*/); + if (!m_ofsLog) + { + m_strLogFile = NULL; + m_bOpened = false; + } + else + { + m_bOpened = true; + //no way with gcc3.0 m_ofsLog.setbuf(NULL, 0); + } + } + return m_bOpened; +} + +// +// Operator(): +// + +// useful variable for returning an invalid ofstream to kill off any +// output to the logfile with wrong loglevel. +static ofstream ofsInvalid; + +ostream& GlobalLog::operator()() +{ + // Ensure the current file is open: + if (!OpenLogFile()) // if it can't be opened, shortcut everything: + return ofsInvalid; + + time_t tNow = time(NULL); + struct tm* ptm = localtime(&tNow); + + char cOldFill = m_ofsLog.fill('0'); + m_ofsLog << setw(4) << ptm->tm_year + 1900 << '-' + << setw(2) << ptm->tm_mon << '-' + << setw(2) << ptm->tm_mday << ' ' + << setw(2) << ptm->tm_hour << ':' + << setw(2) << ptm->tm_min << ':' + << setw(2) << ptm->tm_sec << ' ' + << "FTE" << ' '; + m_ofsLog.fill(cOldFill); + return m_ofsLog; +} + +FunctionLog::FunctionLog(GlobalLog& gl, const char* funcName, unsigned long line) + : log(gl), func(funcName), myIndentLevel(++log.indent), indentChar('+') +{ + OutputLine(line) << "Entered function" << ENDLINE; +} + +FunctionLog::~FunctionLog() +{ + indentChar = '+'; + OutputLine() << "Exited function" << ENDLINE; + --log.indent; +} + +ostream& FunctionLog::RC(unsigned long line) +{ + indentChar = '!'; + return OutputLine() << "{" << line << "} Returning rc = "; +} + +ostream& FunctionLog::OutputIndent(ostream& os) +{ + os << FillChar('|', myIndentLevel - 1); + //for (int i = 1; i < myIndentLevel; ++i) + // os << '|'; + os << indentChar << ' '; + indentChar = '|'; // reset it to |'s. + return os; +} + +ostream& Log__osBinChar(ostream& os, char const& c) +{ + char const cOldFill = os.fill('0'); + os << (isprint(c) ? c : '.') << + " [0x" << hex << (int)c << dec << "]"; + os.fill(cOldFill); + return os; +} + +ostream& Log__osFillChar(ostream& os, char const& c, size_t const& len) +{ + for (size_t i = 0; i < len; ++i) + os << c; + return os; +} + +#define LINE_LENGTH 8 +void Log__BinaryData(FunctionLog& LOGOBJNAME, void* bin_data, size_t len, unsigned long line) +{ + for (size_t i = 0; i < len; i += LINE_LENGTH) + { + ostream& os = LOGOBJNAME.OutputLine(line); + size_t j; + + // as characters + for (j = i; j < i + LINE_LENGTH; ++j) + { + if (j < len) + { + char const c = ((char*)bin_data)[i+j]; + os << (isprint(c) ? c : '.'); + } + else + { + os << ' '; + } + } + os << " ["; + // as hex values + char const cOldFill = os.fill('0'); + for (j = i; j < i + LINE_LENGTH; ++j) + { + if (j < len) + { + int const c = ((char*)bin_data)[i+j]; + if (j != i) os << ','; + os << hex << setw(2) << c << dec; + } + else + { + os << " "; + } + } + os.fill(cOldFill); + os << ']' << ENDLINE; + } +} + +#endif // FTE_NO_LOGGING diff --git a/src/log.h b/src/log.h new file mode 100644 index 0000000..ba500c9 --- /dev/null +++ b/src/log.h @@ -0,0 +1,306 @@ +// +// General Logging... IN A CLASS! :-) +// + +/******************************************************************** + +The author, Darin McBride, explicitly places this module under the +LGPL license. This module must remain free for use, but will not +cause software that uses it to be required to be under the GPL or +any of its derivitives. + +********************************************************************/ + +/** + +Class-based, OO-based logging + +This is intended to be used as a trace utility in C++, if you follow the +following conventions. Note that all macros are intended to work like +function calls - so you still need the terminating semicolon. + +At the top of each function, you must use STARTFUNC(x). The parameter to +this macro is the name of the function. For example, STARTFUNC("main"). + +At the end of each function, or wherever you return from, use one of: + +ENDFUNCRC - trace the return code +ENDFUNCRC_SAFE - same as above, but can be used when returning the + value of something with side effects +ENDFUNCAS - trace the return code, but pretend it's a different type +ENDFUNCAS_SAFE - trace the return code of something with side effects, + as if it were another type. + +Finally, to log trace points throughout your code, use the LOG() macro +as if it were an ostream. To terminate each line, do not use endl, but +use the ENDLINE macro. Yes, currently it's the same thing, but I'm +reserving the right to change that in the future. + +For example: + +int main() +{ + STARTFUNC("main"); + + LOG << "About to call foo" << ENDLINE; + SomeObjectType baz; + foo(baz); + + ENDFUNCRC(0); + // no return - the macro does this for us. +} + +void foo(SomeObjectType bar) +{ + STARTFUNC("foo") + // assumes bar has some meaningful way to be put into an ostream: + LOG << "bar = " << bar << ENDLINE; + // as void, no need to endfunc. +} + +ENDFUNCRC_SAFE is used such as: + +ENDFUNCRC_SAFE(foo++); // side effect only happens once. +// was: return foo++ + +The AS versions are only used to log as a different type than it currently +is. For example, to log a HANDLE as if it were an unsigned long: + +HANDLE foo; +ENDFUNCAS(unsigned long, foo); +// was: return foo + +Finally, ENDFUNCAS_SAFE: + +ENDFUNCAS_SAFE(HANDLE, unsigned long, GetNextHandle()); +// was: return GetNextHandle() + +*/ + + +#ifndef __LOGGING_HPP +#define __LOGGING_HPP + +#if defined(NO_NEW_CPP_FEATURES) +#include +#include +#include +#include +#else +#include +#include +#include +#include +#endif + +#define bool int +#define true 1 +#define false 0 + +#if !defined(NO_NEW_CPP_FEATURES) +using namespace std; +#endif + +#ifndef FTE_NO_LOGGING + +/** + * GlobalLog handles the actual logging. + */ +class GlobalLog +{ + friend class FunctionLog; +private: + char const* m_strLogFile; + ofstream m_ofsLog; + + bool m_bOpened; + + int indent; + + ostream& operator()(); + +public: + GlobalLog() : m_strLogFile(NULL), m_bOpened(false) {} + GlobalLog(char const* strLogFile) : m_strLogFile(strdup(strLogFile)), m_bOpened(false) {} + + virtual ~GlobalLog() {free((void*)m_strLogFile);} + + void SetLogFile(char const* strNewLogFile) + { + if (m_strLogFile == NULL || + strNewLogFile == NULL || + strcmp(m_strLogFile,strNewLogFile) != 0) + { + free((void*)m_strLogFile); + m_strLogFile = strNewLogFile == NULL ? NULL : strdup(strNewLogFile); + m_bOpened = false; + } + } + + operator bool() { return !m_ofsLog.fail(); } + +protected: + bool OpenLogFile(); // actually open it +}; + +extern GlobalLog globalLog; + +/** + * FunctionLog is the local object that handles logging inside a function. + * All work is put through here. + */ +class FunctionLog +{ +private: + GlobalLog& log; + char const* func; + int myIndentLevel; + char indentChar; +public: + // Enter: + FunctionLog(GlobalLog& gl, const char* funcName, unsigned long line); + + // Exit: + ~FunctionLog(); + + // RC? + ostream& RC(unsigned long line); + +private: + ostream& OutputLine() + { return OutputIndent(log()) << '[' << func << "] "; } + +public: + // output line. + ostream& OutputLine(unsigned long line) + { return OutputLine() << '{' << line << "} "; } + +private: + ostream& OutputIndent(ostream& os); +}; + +#define LOGOBJNAME functionLog__obj +#define LOG LOGOBJNAME.OutputLine(__LINE__) +#define ENDLINE endl + +#define STARTFUNC(func) FunctionLog LOGOBJNAME(globalLog, func, __LINE__) +#define ENDFUNCRC(rc) do { LOGOBJNAME.RC(__LINE__) << (rc) << ENDLINE; return (rc); } while (0) +#define ENDFUNCRC_SAFE(type,rc) do { type LOG__RC = (rc); LOGOBJNAME.RC(__LINE__) << LOG__RC << ENDLINE; return LOG__RC; } while (0) +#define ENDFUNCAS(type,rc) do { LOGOBJNAME.RC(__LINE__) << (type)(rc) << ENDLINE; return (rc); } while (0) +#define ENDFUNCAS_SAFE(logtype,rctype,rc) do { rctype LOG__RC = (rc); LOGOBJNAME.RC(__LINE__) << (logtype)LOG__RC << ENDLINE; return LOG__RC; } while (0) +#define BOOLYESNO(x) ((x) ? "YES" : "NO") + +/********************************************************************/ + +/* Utility ostream functions. + +These are functions that only have anything to do with logging because +logging is the only place we use IO streams. They're here to make tracing +easier to capture more information. + +********************************************************************** +FUNCTION + BinChar(char) + +CLASS + IO Manipulator + +SAMPLE + LOG << "this char is: " << BinChar(CharP) << ENDLINE; + +DESCRIPTION + BinChar will insert the character followed by the hex value in + brackets. If the character is non-printable, it will display as a + dot. +********************************************************************** +FUNCTION + FillChar(char, length) + +CLASS + IO Manipulator + +SAMPLE + LOG << FillChar('*', 50) << ENDLINE; + +DESCRIPTION + FillChar is available for pretty-printing. Use sparingly, if at + all. +********************************************************************** +FUNCTION + LOGBINARYDATA(char*, int len) + +CLASS + Macro + +SAMPLE + LOG << "The value of some_binary_data is:" << ENDLINE + LOGBINARYDATA(some_binary_data, int len); + +DESCRIPTION + This macro will log some structure or array in basically a + memory-dump style: 8 characters, followed by 8 hex values. If + any character is non-printable, it will display as a dot. +********************************************************************** + +*/ +#define DECLARE_OSTREAM_FUNC1(type1) \ + class ostream_func1_##type1 { \ + private: \ + ostream& (*osfunc)(ostream&, type1 const&); \ + type1 const& o1; \ + public: \ + ostream_func1_##type1(ostream& (*osfunc_)(ostream&, type1 const&), type1 const& o1_) : osfunc(osfunc_), o1(o1_) {} \ + ostream& operator()(ostream& os) const { return osfunc(os, o1); } \ + }; \ + inline ostream& operator <<(ostream& os, ostream_func1_##type1 const& ofunc) \ + { return ofunc(os); } + +#define DECLARE_OSTREAM_FUNC2(type1,type2) \ + class ostream_func2_##type1##_##type2 { \ + private: \ + ostream& (*osfunc)(ostream&, type1 const&, type2 const&); \ + type1 const& o1; \ + type2 const& o2; \ + public: \ + ostream_func2_##type1##_##type2(ostream& (*osfunc_)(ostream&, type1 const&, type2 const&), \ + type1 const& o1_, type2 const& o2_) : \ + osfunc(osfunc_), o1(o1_), o2(o2_) {} \ + ostream& operator()(ostream& os) const { return osfunc(os, o1, o2); } \ + }; \ + inline ostream& operator <<(ostream& os, ostream_func2_##type1##_##type2 const& ofunc) \ + { return ofunc(os); } + +DECLARE_OSTREAM_FUNC1(char); +DECLARE_OSTREAM_FUNC2(char, size_t); + +ostream& Log__osBinChar(ostream&, char const&); +inline ostream_func1_char BinChar(char c) +{ return ostream_func1_char(Log__osBinChar, c); } + +ostream& Log__osFillChar(ostream&, char const&, size_t const&); +inline ostream_func2_char_size_t FillChar(char const& c, size_t const& num) +{ return ostream_func2_char_size_t(Log__osFillChar, c, num); } + + +void Log__BinaryData(FunctionLog&, void* bin_data, size_t len, unsigned long line); +#define LOGBINARYDATA(bin_data,len) Log__BinaryData(LOGOBJNAME,bin_data,len, __LINE__) + +#else // defined NO_LOGGING + +#define LOG while (0) { cout +#define ENDLINE endl; } + +#define STARTFUNC(func) +#define ENDFUNCRC(rc) return rc +#define ENDFUNCRC_SAFE(type,rc) return rc +#define ENDFUNCAS(type,rc) return rc +#define ENDFUNCAS_SAFE(logtype,rctype,rc) return rc +#define BOOLYESNO(x) ((x) ? "YES" : "NO") + +//Replacements for utility functions. +#define BinChar(c) c +#define LOGBINARYDATA(b,l) + +#endif // NO_LOGGING + +#endif // __LOGGING_HPP diff --git a/src/memicmp.cpp b/src/memicmp.cpp new file mode 100644 index 0000000..8e7740b --- /dev/null +++ b/src/memicmp.cpp @@ -0,0 +1,32 @@ +// Contributed by Markus F.X.J. Oberhumer + +#include +#include + +#if defined(__DJGPP__) || defined(UNIX) + +#ifdef __cplusplus +extern "C" +#endif +int memicmp(const void *s1, const void *s2, size_t n) +{ + if (n != 0) + { + const unsigned char *p1 = (const unsigned char *) s1; + const unsigned char *p2 = (const unsigned char *) s2; + + do { + if (*p1 != *p2) + { + int c = toupper(*p1) - toupper(*p2); + if (c) + return c; + } + p1++; p2++; + } while (--n != 0); + } + return 0; +} + +#endif + diff --git a/src/menu_text.cpp b/src/menu_text.cpp new file mode 100644 index 0000000..9992eb9 --- /dev/null +++ b/src/menu_text.cpp @@ -0,0 +1,666 @@ +/* menu_text.cpp + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include "console.h" +#include "gui.h" +#include "c_mode.h" +#include "c_color.h" + +class UpMenu { +public: + class UpMenu *up; + int id; + int vert; + int x, y, w, h; +}; + +int GetHOfsItem(int id, int cur) { + int pos = 2; + int i, len; + + for (i = 0; i < Menus[id].Count; i++) { + if (i == cur) return pos; + if (Menus[id].Items[i].Name) { + len = CStrLen(Menus[id].Items[i].Name); + pos += len + 2; + } else + pos++; + } + return -1; +} + +int GetHPosItem(int id, int X) { + int pos = 1; + int i, len; + + for (i = 0; i < Menus[id].Count; i++) { + if (Menus[id].Items[i].Name) { + len = CStrLen(Menus[id].Items[i].Name); + if (X >= pos && X <= pos + len + 1) return i; + pos += len + 2; + } else + pos++; + } + return -1; +} + +int DrawHMenu(int x, int y, int id, int active) { + int pos = 1; + TDrawBuffer B; + int i, len; + TAttr color1, color2; + int Cols, Rows; + + ConQuerySize(&Cols, &Rows); + + MoveChar(B, 0, Cols, ' ', hcMenu_Background, Cols); + if (id != -1) { + for (i = 0; i < Menus[id].Count; i++) { + if (i == active) { + color1 = hcMenu_ActiveItem; + color2 = hcMenu_ActiveChar; + } else { + color1 = hcMenu_NormalItem; + color2 = hcMenu_NormalChar; + } + + if (Menus[id].Items[i].Name) { + len = CStrLen(Menus[id].Items[i].Name); + MoveChar(B, pos, Cols, ' ', color1, len + 2); + MoveCStr(B, pos + 1, Cols, Menus[id].Items[i].Name, color1, color2, len); + pos += len + 2; + } else { + MoveChar(B, pos, Cols, ConGetDrawChar(DCH_V), hcMenu_Background, 1); + pos++; + } + } + } + ConPutBox(x, y, Cols - x, 1, B); + return 1; +} + +int GetVPosItem(int id, int w, int X, int Y) { + if (Y <= 0 || Y > Menus[id].Count) return -1; + if (Menus[id].Items[Y - 1].Name == 0) return -1; + if (X <= 0 || X >= w - 1) return -1; + return Y - 1; +} + +int GetVSize(int id, int &X, int &Y) { + int xsize = 0; + int len; + + Y = Menus[id].Count; + for (int i = 0; i < Y; i++) { + len = 0; + if (Menus[id].Items[i].Name) + len = CStrLen(Menus[id].Items[i].Name); + if (len > xsize) + xsize = len; + } + X = xsize; + return 0; +} + + +int DrawVMenu(int x, int y, int id, int active) { + TDrawBuffer B; + int i, len; + TAttr color1, color2; + int w, h; + + if (id == -1) return -1; + + GetVSize(id, w, h); + w += 4; + h += 2; + + MoveChar(B, 0, w, ConGetDrawChar(DCH_H), hcMenu_Background, w); + MoveCh(B, ConGetDrawChar(DCH_C1), hcMenu_Background, 1); + MoveCh(B + w - 1, ConGetDrawChar(DCH_C2), hcMenu_Background, 1); + ConPutBox(x, y, w, 1, B); + for (i = 0; i < Menus[id].Count; i++) { + if (i == active) { + color1 = hcMenu_ActiveItem; + color2 = hcMenu_ActiveChar; + } else { + color1 = hcMenu_NormalItem; + color2 = hcMenu_NormalChar; + } + if (Menus[id].Items[i].Name) { + char name[128]; + char *arg = 0; + int len2 = 0; + + strcpy(name, Menus[id].Items[i].Name); + arg = strchr(name, '\t'); + if (arg) + *arg++ = 0; + + len = CStrLen(name); + if (arg) + len2 = CStrLen(arg); + + MoveChar(B, 0, w, ' ', color1, w); + MoveCh(B, ConGetDrawChar(DCH_V), hcMenu_Background, 1); + MoveCh(B + w - 1, ConGetDrawChar(DCH_V), hcMenu_Background, 1); + + MoveCStr(B, 2, len + 2, Menus[id].Items[i].Name, color1, color2, len); + if (arg) + MoveCStr(B, w - len2 - 2, w + 4, arg, color1, color2, len2); + + if (Menus[id].Items[i].SubMenu != -1) { + MoveCh(B + w - 2, ConGetDrawChar(DCH_RPTR), color1, 1); + } + } else { + MoveChar(B, 0, w, ConGetDrawChar(DCH_H), hcMenu_Background, w); + MoveCh(B, ConGetDrawChar(DCH_V), hcMenu_Background, 1); + MoveCh(B + w - 1, ConGetDrawChar(DCH_V), hcMenu_Background, 1); + } + ConPutBox(x, y + i + 1, w, 1, B); + } + MoveChar(B, 0, w, ConGetDrawChar(DCH_H), hcMenu_Background, w); + MoveCh(B, ConGetDrawChar(DCH_C3), hcMenu_Background, 1); + MoveCh(B + w - 1, ConGetDrawChar(DCH_C4), hcMenu_Background, 1); + ConPutBox(x, y + Menus[id].Count + 1, w, 1, B); + return 1; +} + +int ExecVertMenu(int x, int y, int id, TEvent &E, UpMenu *up) { + int cur = 0; + int abort; + int w, h; + PCell c; + PCell SaveC = 0; + int SaveX, SaveY, SaveW, SaveH; + int wasmouse = 0; + UpMenu here; + int dovert = 0; + int rx; + int Cols, Rows; + + ConQuerySize(&Cols, &Rows); + + here.up = up; + + if (x < 0) x = 0; + if (y < 0) y = 0; + + GetVSize(id, w, h); + w += 4; + h += 2; + + if (w > Cols) w = Cols; + if (h > Rows) h = Rows; + + if (x + w > Cols) + if (up && up->x == 0 && up->y == 0 && up->h == 1) { + x = Cols - w; + } else { + if (up) + x = up->x - w + 1; + else + x = x - w + 1; + } + if (y + h > Rows) + if (up) + y = y - h + 3; + else { + y = y - h + 1; + } + if (x < 0) x = 0; + if (y < 0) y = 0; + + here.x = x; + here.y = y; + here.w = w; + here.h = h; + here.id = id; + here.vert = 1; + + c = (PCell) malloc(w * h * sizeof(TCell)); + if (c) + ConGetBox(x, y, w, h, c); + + SaveC = c; + SaveX = x; + SaveY = y; + SaveW = w; + SaveH = h; + + if (E.What == evMouseMove || E.What == evMouseDown) { + } + if (E.What & evMouse) { + cur = GetVPosItem(id, w, E.Mouse.X - x, E.Mouse.Y - y); + dovert = 0; + wasmouse = 1; + E.What = evNone; + } + abort = -2; + while (abort == -2) { + DrawVMenu(x, y, id, cur); + if (dovert) { + if (cur != -1) { + if (Menus[id].Items[cur].SubMenu != -1) { + rx = ExecVertMenu(x + w - 1, y + cur, + Menus[id].Items[cur].SubMenu, E, &here); + if (rx == 1) { + abort = 1; + continue; + } else if (rx == -3) { + abort = -3; + break; + } else + abort = -2; + + } + } + } + ConHideCursor(); + do { + ConGetEvent(evCommand | evMouseDown | evMouseMove | evMouseUp | evKeyDown | evNotify, &E, -1, 1); + if (E.What & evNotify) + gui->DispatchEvent(frames, frames->Active, E); + } while (E.What & evNotify); + if (E.What & evMouse) { + //fprintf(stderr, "Mouse: %d %d %d\n", E.What, E.Mouse.X, E.Mouse.Y); + } + dovert = 0; + switch (E.What) { + case evCommand: + if (E.Msg.Command == cmResize) abort = -3; + break; + case evKeyDown: + switch (kbCode(E.Key.Code)) { + case kbPgDn: + case kbEnd: cur = Menus[id].Count; + case kbUp: + { + int x = cur; + + do { + cur--; + if (cur < 0) cur = Menus[id].Count - 1; + } while (cur != x && Menus[id].Items[cur].Name == 0); + } + break; + case kbPgUp: + case kbHome: cur = -1; + case kbDown: + { + int x = cur; + do { + cur++; + if (cur >= Menus[id].Count) cur = 0; + } while (cur != x && Menus[id].Items[cur].Name == 0); + } + break; + case kbEsc: abort = -1; break; + case kbEnter: + if (cur != -1) { + if (Menus[id].Items[cur].SubMenu < 0) { + E.What = evCommand; + E.Msg.View = frames->Active; + E.Msg.Command = Menus[id].Items[cur].Cmd; + abort = 1; + } else { + dovert = 1; + } + } + break; + case kbLeft: + case kbRight: + gui->ConPutEvent(E); + abort = -1; + break; + default: + if (isAscii(E.Key.Code)) { + char cc; + int i; + + cc = char(toupper(char(E.Key.Code & 0xFF))); + + for (i = 0; i < Menus[id].Count; i++) { + if (Menus[id].Items[i].Name) { + char *o = strchr(Menus[id].Items[i].Name, '&'); + if (o) + if (toupper(o[1]) == cc) { + cur = i; + if (cur != -1) { + if (Menus[id].Items[cur].SubMenu == -1) { + E.What = evCommand; + E.Msg.View = frames->Active; + E.Msg.Command = Menus[id].Items[cur].Cmd; + abort = 1; + } else { + dovert = 1; + } + } + break; + } + } + } + } + } + break; + case evMouseDown: + if (E.Mouse.X >= x && E.Mouse.Y >= y && + E.Mouse.X < x + w && E.Mouse.Y < y + h) + { + cur = GetVPosItem(id, w, E.Mouse.X - x, E.Mouse.Y - y); + } else { + if (up) + gui->ConPutEvent(E); + abort = -1; + } + wasmouse = 1; + dovert = 1; + break; + case evMouseMove: + if (E.Mouse.Buttons) { + dovert = 1; + if (E.Mouse.X >= x && E.Mouse.Y >= y && + E.Mouse.X < x + w && E.Mouse.Y < y + h) + { + cur = GetVPosItem(id, w, E.Mouse.X - x, E.Mouse.Y - y); + } else { + UpMenu *p = up; + int first = 1; + + if (wasmouse) { + while (p) { + if (E.Mouse.X >= p->x && E.Mouse.Y >= p->y && + E.Mouse.X < p->x + p->w && E.Mouse.Y < p->y + p->h) + { + if (first == 1) { + if (p->vert) { + int i = GetVPosItem(p->id, p->w, E.Mouse.X - p->x, E.Mouse.Y - p->y); + if (i != -1) + if (Menus[p->id].Items[i].SubMenu == id) break; + } else { + int i = GetHPosItem(p->id, E.Mouse.X); + if (i != -1) + if (Menus[p->id].Items[i].SubMenu == id) break; + } + first = 0; + } + gui->ConPutEvent(E); + abort = -1; + break; + } + first = 0; + p = p->up; + } + cur = -1; + } else + cur = -1; + } + } + break; + case evMouseUp: + if (E.Mouse.X >= x && E.Mouse.Y >= y && + E.Mouse.X < x + w && E.Mouse.Y < y + h) + { + cur = GetVPosItem(id, w, E.Mouse.X - x, E.Mouse.Y - y); + } + if (cur == -1) { + if (up) { + UpMenu *p = up; + cur = 0; + if (E.Mouse.X >= p->x && E.Mouse.Y >= p->y && + E.Mouse.X < p->x + p->w && E.Mouse.Y < p->y + p->h) + { + if (p->vert) { + int i = GetVPosItem(p->id, p->w, E.Mouse.X - p->x, E.Mouse.Y - p->y); + if (i != -1) + if (Menus[p->id].Items[i].SubMenu == id) break; + } else { + int i = GetHPosItem(p->id, E.Mouse.X); + if (i != -1) + if (Menus[p->id].Items[i].SubMenu == id) break; + } + abort = -1; + } + } else + abort = -1; + if (E.Mouse.X >= x && E.Mouse.Y >= y && + E.Mouse.X < x + w && E.Mouse.Y < y + h); + else { + gui->ConPutEvent(E); + abort = -3; + } + } else { + if (Menus[id].Items[cur].Name != 0 && + Menus[id].Items[cur].SubMenu == -1) + { + E.What = evCommand; + E.Msg.View = frames->Active; + E.Msg.Command = Menus[id].Items[cur].Cmd; + //fprintf(stderr, "Command set = %d %d %d\n", id, cur, Menus[id].Items[cur].Cmd); + abort = 1; + } + } + break; + } + } + if (SaveC) { + ConPutBox(SaveX, SaveY, SaveW, SaveH, SaveC); + free(SaveC); + SaveC = 0; + } + ConShowCursor(); + if (up && abort == -3) return -3; + return (abort == 1) ? 1 : -1; +} + +int ExecMainMenu(TEvent &E, char sub) { + int cur = 0; + int id = GetMenuId(frames->Menu); + int abort; + int dovert = 1; + int rx; + static UpMenu top = { 0, 0, 0, 0, 0, 0, 1 }; + PCell topline[ConMaxCols]; + int Cols, Rows; + + ConQuerySize(&Cols, &Rows); + + top.x = 0; + top.y = 0; + top.h = 1; + top.w = Cols; + top.id = id; + top.vert = 0; + + ConGetBox(0, 0, Cols, 1, (PCell) topline); + + if (sub != 0) { + int i; + + for (i = 0; i < Menus[id].Count; i++) { + if (Menus[id].Items[i].Name) { + char *o = strchr(Menus[id].Items[i].Name, '&'); + if (o) + if (toupper(o[1]) == toupper(sub)) { + cur = i; + break; + } + } + } + } + + if (E.What == evMouseDown) { + cur = GetHPosItem(id, E.Mouse.X); + dovert = 1; + } + abort = -2; + while (abort == -2) { + DrawHMenu(0, 0, id, cur); + if (dovert) { + if (cur != -1) { + if (Menus[id].Items[cur].SubMenu != -1) { + rx = ExecVertMenu(GetHOfsItem(id, cur) - 2, 1, + Menus[id].Items[cur].SubMenu, E, &top); + if (rx == 1) { + abort = 1; + continue; + } else if (rx == -3) { + abort = -1; + break; + } else + abort = -2; + } + } + } + ConHideCursor(); + do { + ConGetEvent(evCommand | evMouseDown | evMouseMove | evMouseUp | evKeyDown | evNotify, &E, -1, 1); + if (E.What & evNotify) + gui->DispatchEvent(frames, frames->Active, E); + } while (E.What & evNotify); + dovert = 0; + switch (E.What) { + case evCommand: + if (E.Msg.Command == cmResize) abort = -1; + break; + case evKeyDown: + switch (kbCode(E.Key.Code)) { + case kbEnd: cur = Menus[id].Count; + case kbLeft: + dovert = 1; + { + int x = cur; + do { + cur--; + if (cur < 0) cur = Menus[id].Count - 1; + } while (cur != x && Menus[id].Items[cur].Name == 0); + } + break; + case kbHome: cur = -1; + case kbRight: + dovert = 1; + { + int x = cur; + do { + cur++; + if (cur >= Menus[id].Count) cur = 0; + } while (cur != x && Menus[id].Items[cur].Name == 0); + } + break; + case kbEsc: abort = -1; dovert = 0; break; + case kbEnter: + if (cur != -1) { + if (Menus[id].Items[cur].SubMenu == -1) { + E.What = evCommand; + E.Msg.View = frames->Active; + E.Msg.Command = Menus[id].Items[cur].Cmd; + abort = 1; + } else { + dovert = 1; + } + } + break; + default: + if (isAscii(E.Key.Code)) { + char cc; + int i; + + cc = char(toupper(char(E.Key.Code & 0xFF))); + + for (i = 0; i < Menus[id].Count; i++) { + if (Menus[id].Items[i].Name) { + char *o = strchr(Menus[id].Items[i].Name, '&'); + if (o) + if (toupper(o[1]) == cc) { + cur = i; + if (cur != -1) { + if (Menus[id].Items[cur].SubMenu == -1) { + E.What = evCommand; + E.Msg.View = frames->Active; + E.Msg.Command = Menus[id].Items[cur].Cmd; + abort = 1; + } else { + dovert = 1; + } + } + break; + } + } + } + } + break; + } + break; + case evMouseDown: + if (E.Mouse.Y == 0) { + int oldcur = cur; + cur = GetHPosItem(id, E.Mouse.X); + if (cur == oldcur) { + abort = -1; + } + } else { + cur = -1; + abort = -1; + } + dovert = 1; + break; + case evMouseMove: + if (E.Mouse.Buttons) { + if (E.Mouse.Y == 0) + cur = GetHPosItem(id, E.Mouse.X); + else + cur = -1; + dovert = 1; + } + break; + case evMouseUp: + if (E.Mouse.Y == 0) + cur = GetHPosItem(id, E.Mouse.X); + if (cur == -1) + abort = -1; + else { + if (Menus[id].Items[cur].Name != 0 && + Menus[id].Items[cur].SubMenu == -1) + { + E.What = evCommand; + E.Msg.View = frames->Active; + E.Msg.Command = Menus[id].Items[cur].Cmd; + abort = 1; + } + } + break; + } + } + DrawHMenu(0, 0, id, -1); + ConPutBox(0, 0, Cols, 1, (PCell) topline); + ConShowCursor(); + return (abort == 1) ? 1 : -1; +} + +void GFrame::DrawMenuBar() { + int id = GetMenuId(Menu); + + DrawHMenu(0, 0, id, -1); +} + +extern TEvent NextEvent; + +int GFrame::PopupMenu(const char *Name) { + NextEvent.What = evCommand; + NextEvent.Msg.Command = cmPopupMenu; + NextEvent.Msg.Param1 = GetMenuId(Name); + return 0; +} diff --git a/src/mkdefcfg.pl b/src/mkdefcfg.pl new file mode 100644 index 0000000..f25420b --- /dev/null +++ b/src/mkdefcfg.pl @@ -0,0 +1,43 @@ +#!perl -w + +$n = 1; +$buf = ""; +$out = ""; +local($infile, $outfile) = @ARGV; +if(defined($infile)) {open(INFILE, "<$infile"); } +else { open(INFILE, "<&STDIN"); } +if(defined($outfile)) {open(OUTFILE, ">$outfile"); } +else { open(OUTFILE, ">&STDOUT"); } +print OUTFILE "/* do not edit */\nchar DefaultConfig[] = {\n"; +binmode INFILE; # NT needs this +local($len); +while (($len = read(INFILE, $buf, 256)) > 0) { + #$buf =~ s/(.)/sprintf "0x%02X", ord($1))/goe; + #for ($i = 0; $i < $len; $i++) { + # $out .= sprintf "0x%02X", ord(substr($buf, $i, 1,)); + # if ($n++ % 10) { + # $out .= ", "; + # } else { + # $out .= ",\n"; + # } + #} + + @c = split(//, $buf); + for ($i = 0; $i < $len; $i++) { + $out .= sprintf("0x%02X", ord($c[$i])); + if ($n++ % 10) { + $out .= ", "; + } else { + $out .= ",\n"; + } + } + + print OUTFILE $out; + $out = ""; + print STDERR "."; +} +print OUTFILE "\n};\n"; +close(INFILE); +close(OUTFILE); +print STDERR "\n"; + diff --git a/src/namemaps.h b/src/namemaps.h new file mode 100644 index 0000000..951ca8f --- /dev/null +++ b/src/namemaps.h @@ -0,0 +1,27 @@ +/* M$VC++ !!! */ +#ifndef __NAMEMAPS_H__ +#define __NAMEMAPS_H__ + +#define access _access +#define chmod _chmod +#define chsize _chsize +#define close _close +#define creat _creat +#define dup _dup +#define dup2 _dup2 +#define eof _eof +#define filelength _filelength +#define isatty _isatty +#define locking _locking +#define lseek _lseek +#define mktemp _mktemp +#define open _open +#define read _read +#define setmode _setmode +#define sopen _sopen +#define tell _tell +#define umask _umask +#define unlink _unlink +#define write _write + +#endif diff --git a/src/o_buffer.cpp b/src/o_buffer.cpp new file mode 100644 index 0000000..fd5a138 --- /dev/null +++ b/src/o_buffer.cpp @@ -0,0 +1,1512 @@ +/* o_buffer.cpp + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#include "fte.h" + +SearchReplaceOptions LSearch = { 0 }; +int suspendLoads = 0; + +EViewPort *EBuffer::CreateViewPort(EView *V) { + V->Port = new EEditPort(this, V); + AddView(V); + + if (Loaded == 0 && !suspendLoads) { + Load(); + +#ifdef CONFIG_OBJ_MESSAGES + if (CompilerMsgs) + CompilerMsgs->FindFileErrors(this); +#endif + + markIndex.retrieveForBuffer(this); + +#ifdef CONFIG_HISTORY + int r, c; + + if (RetrieveFPos(FileName, r, c) == 1) + SetNearPosR(c, r); + //printf("setting to c:%d r:%d f:%s", c, r, FileName); + V->Port->GetPos(); + V->Port->ReCenter = 1; +#endif + } + return V->Port; +} + +EEditPort::EEditPort(EBuffer *B, EView *V): EViewPort(V) { + Buffer = B; + Rows = Cols = 0; + OldTP.Row = -1; + OldTP.Col = -1; + GetPos(); + TP = B->TP; + CP = B->CP; + if (V && V->MView && V->MView->Win) { + V->MView->ConQuerySize(&Cols, &Rows); + Rows--; + } +} + +EEditPort::~EEditPort() { + StorePos(); +} + +void EEditPort::Resize(int Width, int Height) { + Cols = Width; + Rows = Height - 1; + RedrawAll(); +} + +int EEditPort::SetTop(int Col, int Line) { + int A, B; + + if (Line >= Buffer->VCount) Line = Buffer->VCount - 1; + if (Line < 0) Line = 0; + + A = Line; + B = Line + Rows; + + TP.Row = Line; + TP.Col = Col; + + if (A >= Buffer->VCount) A = Buffer->VCount - 1; + if (B >= Buffer->VCount) { + B = Buffer->VCount - 1; + } + Buffer->Draw(Buffer->VToR(A), -1); + return 1; +} + +void EEditPort::StorePos() { + Buffer->CP = CP; + Buffer->TP = TP; +} + +void EEditPort::GetPos() { + CP = Buffer->CP; + TP = Buffer->TP; +} + +void EEditPort::ScrollY(int Delta) { + // optimization + // no need to scroll (clear) entire window which we are about to redraw + if (Delta >= Rows || -Delta >= Rows) + return ; + + if (Delta < 0) { + Delta = -Delta; + if (Delta > Rows) return; + View->MView->ConScroll(csDown, 0, 0, Cols, Rows, hcPlain_Background, Delta); + } else { + if (Delta > Rows) return; + View->MView->ConScroll(csUp, 0, 0, Cols, Rows, hcPlain_Background, Delta); + } +} + +void EEditPort::DrawLine(int L, TDrawBuffer B) { + if (L < TP.Row) return; + if (L >= TP.Row + Rows) return; + if (View->MView->Win->GetViewContext() == View->MView) + View->MView->ConPutBox(0, L - TP.Row, Cols, 1, B); + // printf("%d %d (%d %d %d %d)\n", 0, L - TP.Row, view->sX, view->sY, view->sW, view->sH); +} + +void EEditPort::RedrawAll() { + Buffer->Draw(TP.Row, -1); + /// Redraw(0, 0, Cols, Rows); +} + +int EBuffer::GetContext() { + return CONTEXT_FILE; +} + +void EEditPort::HandleEvent(TEvent &Event) { + EViewPort::HandleEvent(Event); + switch (Event.What) { + case evKeyDown: + { + char Ch; + if (GetCharFromEvent(Event, &Ch)) { + if (Buffer->BeginMacro() == 0) + return ; + Buffer->TypeChar(Ch); + Event.What = evNone; + } + } + break; + case evCommand: + switch (Event.Msg.Command) { + case cmVScrollUp: + Buffer->ScrollDown(1); + Event.What = evNone; + break; + case cmVScrollDown: + Buffer->ScrollUp(1); + Event.What = evNone; + break; + case cmVScrollPgUp: + Buffer->ScrollDown(Rows); + Event.What = evNone; + break; + case cmVScrollPgDn: + Buffer->ScrollUp(Rows); + Event.What = evNone; + break; + case cmVScrollMove: + { + int ypos; + +// fprintf(stderr, "Pos = %d\n\x7", Event.Msg.Param1); + ypos = Buffer->CP.Row - TP.Row; + Buffer->SetNearPos(Buffer->CP.Col, Event.Msg.Param1 + ypos); + SetTop(TP.Col, Event.Msg.Param1); + RedrawAll(); + } + Event.What = evNone; + break; + case cmHScrollLeft: + Buffer->ScrollRight(1); + Event.What = evNone; + break; + case cmHScrollRight: + Buffer->ScrollLeft(1); + Event.What = evNone; + break; + case cmHScrollPgLt: + Buffer->ScrollRight(Cols); + Event.What = evNone; + break; + case cmHScrollPgRt: + Buffer->ScrollLeft(Cols); + Event.What = evNone; + break; + case cmHScrollMove: + { + int xpos; + + xpos = Buffer->CP.Col - TP.Col; + Buffer->SetNearPos(Event.Msg.Param1 + xpos, Buffer->CP.Row); + SetTop(Event.Msg.Param1, TP.Row); + RedrawAll(); + } + Event.What = evNone; + break; + } + break; + case evMouseDown: + case evMouseMove: + case evMouseAuto: + case evMouseUp: + HandleMouse(Event); + break; + } +} +void EEditPort::HandleMouse(TEvent &Event) { + int x, y, xx, yy, W, H; + + View->MView->ConQuerySize(&W, &H); + + x = Event.Mouse.X; + y = Event.Mouse.Y; + + if (Event.What != evMouseDown || y < H - 1) { + xx = x + TP.Col; + yy = y + TP.Row; + if (yy >= Buffer->VCount) yy = Buffer->VCount - 1; + if (yy < 0) yy = 0; + if (xx < 0) xx = 0; + + switch (Event.What) { + case evMouseDown: + if (Event.Mouse.Y == H - 1) + break; + if (View->MView->Win->CaptureMouse(1)) + View->MView->MouseCaptured = 1; + else + break; + + View->MView->MouseMoved = 0; + + if (Event.Mouse.Buttons == 1) { + Buffer->SetNearPos(xx, yy); + switch (Event.Mouse.Count % 5) { + case 1: + break; + case 2: + Buffer->BlockSelectWord(); + break; + case 3: + Buffer->BlockSelectLine(); + break; + case 4: + Buffer->BlockSelectPara(); + break; + } + // Window->Buffer->Redraw(); + if (SystemClipboard) { + Buffer->NextCommand(); + Buffer->BlockCopy(0); + } + Event.What = evNone; + } else if (Event.Mouse.Buttons == 2) { + Buffer->SetNearPos(xx, yy); + } + break; + case evMouseAuto: + case evMouseMove: + if (View->MView->MouseCaptured) { + if (Event.Mouse.Buttons == 1) { + if (!View->MView->MouseMoved) { + if (Event.Mouse.KeyMask == kfCtrl) Buffer->BlockMarkColumn(); + else if (Event.Mouse.KeyMask == kfAlt) Buffer->BlockMarkLine(); + else Buffer->BlockMarkStream(); + Buffer->BlockUnmark(); + if (Event.What == evMouseMove) + View->MView->MouseMoved = 1; + } + Buffer->BlockExtendBegin(); + Buffer->SetNearPos(xx, yy); + Buffer->BlockExtendEnd(); + } else if (Event.Mouse.Buttons == 2) { + if (Event.Mouse.KeyMask == kfAlt) { + } else { + Buffer->SetNearPos(xx, yy); + } + } + + Event.What = evNone; + } + break; +/* case evMouseAuto: + if (View->MView->MouseCaptured) { + Event.What = evNone; + } + break;*/ + case evMouseUp: + if (View->MView->MouseCaptured) + View->MView->Win->CaptureMouse(0); + else + break; + View->MView->MouseCaptured = 0; + if (Event.Mouse.Buttons == 1) { + if (View->MView->MouseMoved) + if (SystemClipboard) { + Buffer->NextCommand(); + Buffer->BlockCopy(0); + } + } + if (Event.Mouse.Buttons == 2) { + if (!View->MView->MouseMoved) { + EEventMap *Map = View->MView->Win->GetEventMap(); + const char *MName = 0; + + if (Map) + MName = Map->GetMenu(EM_LocalMenu); + if (MName == 0) + MName = "Local"; + View->MView->Win->Parent->PopupMenu(MName); + } + } + if (Event.Mouse.Buttons == 4) { + if (SystemClipboard) { + Buffer->NextCommand(); + if (Event.Mouse.KeyMask == 0) + Buffer->BlockPasteStream(); + else if (Event.Mouse.KeyMask == kfCtrl) + Buffer->BlockPasteColumn(); + else if (Event.Mouse.KeyMask == kfAlt) + Buffer->BlockPasteLine(); + } + } + Event.What = evNone; + break; + } + } +} + +void EEditPort::UpdateView() { + Buffer->Redraw(); +} + +void EEditPort::RepaintView() { + RedrawAll(); +} + +void EEditPort::UpdateStatus() { +} + +void EEditPort::RepaintStatus() { + //Buffer->Redraw(); +} + +EEventMap *EBuffer::GetEventMap() { + return FindActiveMap(Mode); +} + +int EBuffer::BeginMacro() { + return NextCommand(); +} + +int EBuffer::ExecCommand(int Command, ExState &State) { + switch (Command) { + case ExMoveUp: return MoveUp(); + case ExMoveDown: return MoveDown(); + case ExMoveLeft: return MoveLeft(); + case ExMoveRight: return MoveRight(); + case ExMovePrev: return MovePrev(); + case ExMoveNext: return MoveNext(); + case ExMoveWordLeft: return MoveWordLeft(); + case ExMoveWordRight: return MoveWordRight(); + case ExMoveWordPrev: return MoveWordPrev(); + case ExMoveWordNext: return MoveWordNext(); + case ExMoveWordEndLeft: return MoveWordEndLeft(); + case ExMoveWordEndRight: return MoveWordEndRight(); + case ExMoveWordEndPrev: return MoveWordEndPrev(); + case ExMoveWordEndNext: return MoveWordEndNext(); + case ExMoveWordOrCapLeft: return MoveWordOrCapLeft(); + case ExMoveWordOrCapRight: return MoveWordOrCapRight(); + case ExMoveWordOrCapPrev: return MoveWordOrCapPrev(); + case ExMoveWordOrCapNext: return MoveWordOrCapNext(); + case ExMoveWordOrCapEndLeft: return MoveWordOrCapEndLeft(); + case ExMoveWordOrCapEndRight: return MoveWordOrCapEndRight(); + case ExMoveWordOrCapEndPrev: return MoveWordOrCapEndPrev(); + case ExMoveWordOrCapEndNext: return MoveWordOrCapEndNext(); + case ExMoveLineStart: return MoveLineStart(); + case ExMoveLineEnd: return MoveLineEnd(); + case ExMovePageStart: return MovePageStart(); + case ExMovePageEnd: return MovePageEnd(); + case ExMovePageUp: return MovePageUp(); + case ExMovePageDown: return MovePageDown(); + case ExMovePageLeft: return MovePageLeft(); + case ExMovePageRight: return MovePageEnd(); + case ExMoveFileStart: return MoveFileStart(); + case ExMoveFileEnd: return MoveFileEnd(); + case ExMoveBlockStart: return MoveBlockStart(); + case ExMoveBlockEnd: return MoveBlockEnd(); + case ExMoveFirstNonWhite: return MoveFirstNonWhite(); + case ExMoveLastNonWhite: return MoveLastNonWhite(); + case ExMovePrevEqualIndent: return MovePrevEqualIndent(); + case ExMoveNextEqualIndent: return MoveNextEqualIndent(); + case ExMovePrevTab: return MovePrevTab(); + case ExMoveNextTab: return MoveNextTab(); + case ExMoveTabStart: return MoveTabStart(); + case ExMoveTabEnd: return MoveTabEnd(); + case ExMoveLineTop: return MoveLineTop(); + case ExMoveLineCenter: return MoveLineCenter(); + case ExMoveLineBottom: return MoveLineBottom(); + case ExMoveBeginOrNonWhite: return MoveBeginOrNonWhite(); + case ExMoveBeginLinePageFile: return MoveBeginLinePageFile(); + case ExMoveEndLinePageFile: return MoveEndLinePageFile(); + case ExScrollLeft: return ScrollLeft(State); + case ExScrollRight: return ScrollRight(State); + case ExScrollDown: return ScrollDown(State); + case ExScrollUp: return ScrollUp(State); + case ExKillLine: return KillLine(); + case ExKillChar: return KillChar(); + case ExKillCharPrev: return KillCharPrev(); + case ExKillWord: return KillWord(); + case ExKillWordPrev: return KillWordPrev(); + case ExKillWordOrCap: return KillWordOrCap(); + case ExKillWordOrCapPrev: return KillWordOrCapPrev(); + case ExKillToLineStart: return KillToLineStart(); + case ExKillToLineEnd: return KillToLineEnd(); + case ExKillBlock: return KillBlock(); + case ExBackSpace: return BackSpace(); + case ExDelete: return Delete(); + case ExCharCaseUp: return CharCaseUp(); + case ExCharCaseDown: return CharCaseDown(); + case ExCharCaseToggle: return CharCaseToggle(); + case ExLineCaseUp: return LineCaseUp(); + case ExLineCaseDown: return LineCaseDown(); + case ExLineCaseToggle: return LineCaseToggle(); + case ExLineInsert: return LineInsert(); + case ExLineAdd: return LineAdd(); + case ExLineSplit: return LineSplit(); + case ExLineJoin: return LineJoin(); + case ExLineNew: return LineNew(); + case ExLineIndent: return LineIndent(); + case ExLineTrim: return LineTrim(); + case ExLineCenter: return LineCenter(); + case ExInsertSpacesToTab: + { + int no; + + if(State.GetIntParam(View, &no) == 0) + no = 0; + return InsertSpacesToTab(no); + } + case ExInsertTab: return InsertTab(); + case ExInsertSpace: return InsertSpace(); + case ExWrapPara: +#ifdef CONFIG_WORDWRAP + return WrapPara(); +#else + return ErFAIL; +#endif + case ExInsPrevLineChar: return InsPrevLineChar(); + case ExInsPrevLineToEol: return InsPrevLineToEol(); + case ExLineDuplicate: return LineDuplicate(); + case ExBlockBegin: return BlockBegin(); + case ExBlockEnd: return BlockEnd(); + case ExBlockUnmark: return BlockUnmark(); + case ExBlockCut: return BlockCut(0); + case ExBlockCopy: return BlockCopy(0); + case ExBlockCutAppend: return BlockCut(1); + case ExBlockCopyAppend: return BlockCopy(1); + case ExClipClear: return ClipClear(); + case ExBlockPaste: return BlockPaste(); + case ExBlockKill: return BlockKill(); + case ExBlockIndent: + { + int saved_persistence, ret_code; + + saved_persistence = BFI(this, BFI_PersistentBlocks); + BFI_SET(this, BFI_PersistentBlocks, 1); + ret_code = BlockIndent(); + BFI_SET(this, BFI_PersistentBlocks, saved_persistence); + return ret_code; + } + case ExBlockUnindent: + { + int saved_persistence, ret_code; + + saved_persistence = BFI(this, BFI_PersistentBlocks); + BFI_SET(this, BFI_PersistentBlocks, 1); + ret_code = BlockUnindent(); + BFI_SET(this, BFI_PersistentBlocks, saved_persistence); + return ret_code; + } + case ExBlockClear: return BlockClear(); + case ExBlockMarkStream: return BlockMarkStream(); + case ExBlockMarkLine: return BlockMarkLine(); + case ExBlockMarkColumn: return BlockMarkColumn(); + case ExBlockCaseUp: return BlockCaseUp(); + case ExBlockCaseDown: return BlockCaseDown(); + case ExBlockCaseToggle: return BlockCaseToggle(); + case ExBlockExtendBegin: return BlockExtendBegin(); + case ExBlockExtendEnd: return BlockExtendEnd(); + case ExBlockReIndent: return BlockReIndent(); + case ExBlockSelectWord: return BlockSelectWord(); + case ExBlockSelectLine: return BlockSelectLine(); + case ExBlockSelectPara: return BlockSelectPara(); + case ExBlockUnTab: return BlockUnTab(); + case ExBlockEnTab: return BlockEnTab(); +#ifdef CONFIG_UNDOREDO + case ExUndo: return Undo(); + case ExRedo: return Redo(); +#else + case ExUndo: return ErFAIL; + case ExRedo: return ErFAIL; +#endif + case ExMatchBracket: return MatchBracket(); + case ExMovePrevPos: return MovePrevPos(); + case ExMoveSavedPosCol: return MoveSavedPosCol(); + case ExMoveSavedPosRow: return MoveSavedPosRow(); + case ExMoveSavedPos: return MoveSavedPos(); + case ExSavePos: return SavePos(); + case ExCompleteWord: return CompleteWord(); + case ExBlockPasteStream: return BlockPasteStream(); + case ExBlockPasteLine: return BlockPasteLine(); + case ExBlockPasteColumn: return BlockPasteColumn(); + case ExShowPosition: return ShowPosition(); + case ExFoldCreate: return FoldCreate(VToR(CP.Row)); + case ExFoldDestroy: return FoldDestroy(VToR(CP.Row)); + case ExFoldDestroyAll: return FoldDestroyAll(); + case ExFoldPromote: return FoldPromote(VToR(CP.Row)); + case ExFoldDemote: return FoldDemote(VToR(CP.Row)); + case ExFoldOpen: return FoldOpen(VToR(CP.Row)); + case ExFoldOpenNested: return FoldOpenNested(); + case ExFoldClose: return FoldClose(VToR(CP.Row)); + case ExFoldOpenAll: return FoldOpenAll(); + case ExFoldCloseAll: return FoldCloseAll(); + case ExFoldToggleOpenClose: return FoldToggleOpenClose(); + case ExFoldCreateAtRoutines: return FoldCreateAtRoutines(); + case ExMoveFoldTop: return MoveFoldTop(); + case ExMoveFoldPrev: return MoveFoldPrev(); + case ExMoveFoldNext: return MoveFoldNext(); + case ExFileSave: return Save(); + case ExFilePrint: return FilePrint(); + case ExBlockPrint: return BlockPrint(); + case ExBlockTrim: return BlockTrim(); + case ExFileTrim: return FileTrim(); + case ExHilitWord: +#ifdef CONFIG_WORD_HILIT + return HilitWord(); +#else + return ErFAIL; +#endif + case ExSearchWordPrev: return SearchWord(SEARCH_BACK | SEARCH_NEXT); + case ExSearchWordNext: return SearchWord(SEARCH_NEXT); + case ExHilitMatchBracket: return HilitMatchBracket(); + case ExToggleAutoIndent: return ToggleAutoIndent(); + case ExToggleInsert: return ToggleInsert(); + case ExToggleExpandTabs: return ToggleExpandTabs(); + case ExToggleShowTabs: return ToggleShowTabs(); + case ExToggleUndo: return ToggleUndo(); + case ExToggleReadOnly: return ToggleReadOnly(); + case ExToggleKeepBackups: return ToggleKeepBackups(); + case ExToggleMatchCase: return ToggleMatchCase(); + case ExToggleBackSpKillTab: return ToggleBackSpKillTab(); + case ExToggleDeleteKillTab: return ToggleDeleteKillTab(); + case ExToggleSpaceTabs: return ToggleSpaceTabs(); + case ExToggleIndentWithTabs: return ToggleIndentWithTabs(); + case ExToggleBackSpUnindents: return ToggleBackSpUnindents(); + case ExToggleWordWrap: return ToggleWordWrap(); + case ExToggleTrim: return ToggleTrim(); + case ExToggleShowMarkers: return ToggleShowMarkers(); + case ExSetLeftMargin: return SetLeftMargin(); + case ExSetRightMargin: return SetRightMargin(); + case ExSetIndentWithTabs: return SetIndentWithTabs(State); + + // stuff with UI + case ExMoveToLine: return MoveToLine(State); + case ExMoveToColumn: return MoveToColumn(State); + case ExFoldCreateByRegexp: return FoldCreateByRegexp(State); +#ifdef CONFIG_BOOKMARKS + case ExPlaceBookmark: return PlaceBookmark(State); + case ExRemoveBookmark: return RemoveBookmark(State); + case ExGotoBookmark: return GotoBookmark(State); +#else + case ExPlaceBookmark: return ErFAIL; + case ExRemoveBookmark: return ErFAIL; + case ExGotoBookmark: return ErFAIL; +#endif + case ExPlaceGlobalBookmark: return PlaceGlobalBookmark(State); + case ExPushGlobalBookmark: return PushGlobalBookmark(); + case ExInsertString: return InsertString(State); + case ExSelfInsert: return SelfInsert(State); + case ExFileReload: return FileReload(State); + case ExFileSaveAs: return FileSaveAs(State); + case ExFileWriteTo: return FileWriteTo(State); + case ExBlockRead: return BlockRead(State); + case ExBlockReadStream: return BlockReadStream(State); + case ExBlockReadLine: return BlockReadLine(State); + case ExBlockReadColumn: return BlockReadColumn(State); + case ExBlockWrite: return BlockWrite(State); + case ExBlockSort: return BlockSort(0); + case ExBlockSortReverse: return BlockSort(1); + case ExFind: return Find(State); + case ExFindReplace: return FindReplace(State); + case ExFindRepeat: return FindRepeat(State); + case ExFindRepeatOnce: return FindRepeatOnce(State); + case ExFindRepeatReverse: return FindRepeatReverse(State); + case ExSearch: return Search(State); + case ExSearchB: return SearchB(State); + case ExSearchRx: return SearchRx(State); + case ExSearchAgain: return SearchAgain(State); + case ExSearchAgainB: return SearchAgainB(State); + case ExSearchReplace: return SearchReplace(State); + case ExSearchReplaceB: return SearchReplaceB(State); + case ExSearchReplaceRx: return SearchReplaceRx(State); + case ExInsertChar: return InsertChar(State); + case ExTypeChar: return TypeChar(State); + case ExChangeMode: return ChangeMode(State); + //case ExChangeKeys: return ChangeKeys(State); + case ExChangeFlags: return ChangeFlags(State); + case ExChangeTabSize: return ChangeTabSize(State); + case ExChangeLeftMargin: return ChangeLeftMargin(State); + case ExChangeRightMargin: return ChangeRightMargin(State); + case ExASCIITable: +#ifdef CONFIG_I_ASCII + return ASCIITable(State); +#else + return ErFAIL; +#endif + case ExCharTrans: return CharTrans(State); + case ExLineTrans: return LineTrans(State); + case ExBlockTrans: return BlockTrans(State); + +#ifdef CONFIG_TAGS + case ExTagFind: return FindTag(State); + case ExTagFindWord: return FindTagWord(State); +#endif + + case ExSetCIndentStyle: return SetCIndentStyle(State); + + case ExBlockMarkFunction: return BlockMarkFunction(); + case ExIndentFunction: return IndentFunction(); + case ExMoveFunctionPrev: return MoveFunctionPrev(); + case ExMoveFunctionNext: return MoveFunctionNext(); + case ExInsertDate: return InsertDate(State); + case ExInsertUid: return InsertUid(); + case ExShowHelpWord: return ShowHelpWord(State); + } + return EModel::ExecCommand(Command, State); +} + +void EBuffer::HandleEvent(TEvent &Event) { + EModel::HandleEvent(Event); +} + +int EBuffer::MoveToLine(ExState &State) { + int No = 0; + + if (State.GetIntParam(View, &No) == 0) { + char Num[10]; + + sprintf(Num, "%d", VToR(CP.Row) + 1); + if (View->MView->Win->GetStr("Goto Line", sizeof(Num), Num, HIST_POSITION) == 0) + return 0; + No = atol(Num); + } + return SetNearPosR(CP.Col, No - 1); +} + +int EBuffer::MoveToColumn(ExState &State) { + int No = 0; + + if (State.GetIntParam(View, &No) == 0) { + char Num[10]; + + sprintf(Num, "%d", CP.Col + 1); + if (View->MView->Win->GetStr("Goto Column", 8, Num, HIST_POSITION) == 0) return 0; + No = atol(Num); + } + return SetNearPos(No - 1, CP.Row); +} + +int EBuffer::FoldCreateByRegexp(ExState &State) { + char strbuf[1024] = ""; + + if (State.GetStrParam(View, strbuf, sizeof(strbuf)) == 0) { + if (View->MView->Win->GetStr("Create Fold Regexp", sizeof(strbuf), strbuf, HIST_REGEXP) == 0) return 0; + } + return FoldCreateByRegexp(strbuf); +} + +#ifdef CONFIG_BOOKMARKS +int EBuffer::PlaceBookmark(ExState &State) { + char name[256] = ""; + EPoint P = CP; + + P.Row = VToR(P.Row); + + if (State.GetStrParam(View, name, sizeof(name)) == 0) + if (View->MView->Win->GetStr("Place Bookmark", sizeof(name), name, HIST_BOOKMARK) == 0) return 0; + return PlaceBookmark(name, P); +} + +int EBuffer::RemoveBookmark(ExState &State) { + char name[256] = ""; + + if (State.GetStrParam(View, name, sizeof(name)) == 0) + if (View->MView->Win->GetStr("Remove Bookmark", sizeof(name), name, HIST_BOOKMARK) == 0) return 0; + return RemoveBookmark(name); +} + +int EBuffer::GotoBookmark(ExState &State) { + char name[256] = ""; + + if (State.GetStrParam(View, name, sizeof(name)) == 0) + if (View->MView->Win->GetStr("Goto Bookmark", sizeof(name), name, HIST_BOOKMARK) == 0) return 0; + return GotoBookmark(name); +} +#endif + +int EBuffer::PlaceGlobalBookmark(ExState &State) { + char name[256] = ""; + EPoint P = CP; + + P.Row = VToR(P.Row); + + if (State.GetStrParam(View, name, sizeof(name)) == 0) + if (View->MView->Win->GetStr("Place Global Bookmark", sizeof(name), name, HIST_BOOKMARK) == 0) return 0; + if (markIndex.insert(name, this, P) == 0) { + Msg(S_ERROR, "Error placing global bookmark %s.", name); + } + return 1; +} + +int EBuffer::PushGlobalBookmark() { + EPoint P = CP; + + P.Row = VToR(P.Row); + EMark *m = markIndex.pushMark(this, P); + if (m) + Msg(S_INFO, "Placed bookmark %s", m->getName()); + return m ? 1 : 0; +} + +int EBuffer::InsertChar(ExState &State) { + char Ch; + int No; + + if (State.GetIntParam(View, &No) == 0) { + TEvent E; + E.What = evKeyDown; + E.Key.Code = View->MView->Win->GetChar("Quote Char:"); + if (!GetCharFromEvent(E, &Ch)) return 0; + No = Ch; + } + if (No < 0 || No > 255) return 0; + Ch = char(No); + return InsertChar(Ch); +} + +int EBuffer::TypeChar(ExState &State) { + char Ch; + int No; + + if (State.GetIntParam(View, &No) == 0) { + TEvent E; + E.What = evKeyDown; + E.Key.Code = View->MView->Win->GetChar(0); + if (!GetCharFromEvent(E, &Ch)) return 0; + No = Ch; + } + if (No < 0 || No > 255) return 0; + Ch = char(No); + return TypeChar(Ch); +} + +int EBuffer::InsertString(ExState &State) { + char strbuf[1024] = ""; + + if (State.GetStrParam(View, strbuf, sizeof(strbuf)) == 0) { + if (View->MView->Win->GetStr("Insert String", sizeof(strbuf), strbuf, HIST_DEFAULT) == 0) + return 0; + } + return InsertString(strbuf, strlen(strbuf)); +} + +extern int LastEventChar; + +int EBuffer::SelfInsert(ExState &/*State*/) { + if (LastEventChar != -1) + return TypeChar(char(LastEventChar)); + return 0; +} + +int EBuffer::FileReload(ExState &/*State*/) { + if (Modified) { + switch (View->MView->Win->Choice(GPC_ERROR, "File Modified", + 2, + "&Reload", + "&Cancel", + "%s", FileName)) + { + case 0: + break; + case 1: + case -1: + default: + return 0; + } + } +// GetNewNumber(); + return Reload(); +} + +int EBuffer::FileSaveAs(char *FName) { + char Name[MAXPATH]; + + if (ExpandPath(FName, Name) == -1) { + View->MView->Win->Choice(GPC_ERROR, "Error", 1, "O&K", "Invalid path: %s.", FName); + return 0; + } + if (FindFile(Name) == 0) { + if (FileExists(Name)) { + switch (View->MView->Win->Choice(GPC_ERROR, "File Exists", + 2, + "&Overwrite", + "&Cancel", + "%s", Name)) + { + case 0: + break; + case 1: + case -1: + default: + return 0; + + } + } + free(FileName); + FileName = strdup(Name); + UpdateTitle(); + return Save(); + } else { + View->MView->Win->Choice(GPC_ERROR, "Error", 1, "O&K", "Already editing '%s.'", Name); + return 0; + } +} + +int EBuffer::FileSaveAs(ExState &State) { + char FName[MAXPATH]; + + strcpy(FName, FileName); + if (State.GetStrParam(View, FName, sizeof(FName)) == 0) + if (View->MView->Win->GetFile("Save As", sizeof(FName), FName, HIST_PATH, GF_SAVEAS) == 0) + return 0; + return FileSaveAs(FName); +} + +int EBuffer::FileWriteTo(char *FName) { + char Name[MAXPATH]; + + if (ExpandPath(FName, Name) == -1) { + View->MView->Win->Choice(GPC_ERROR, "Error", 1, "O&K", "Invalid path: %s.", FName); + return 0; + } + if (FindFile(Name) == 0) { + if (FileExists(Name)) { + switch (View->MView->Win->Choice(GPC_ERROR, "File Exists", + 2, + "&Overwrite", + "&Cancel", + "%s", Name)) + { + case 0: + break; + case 1: + case -1: + default: + return 0; + } + } + return SaveTo(Name); + } else { + View->MView->Win->Choice(GPC_ERROR, "Error", 1, "O&K", "Already editing '%s.'", Name); + return 0; + } +} + +int EBuffer::FileWriteTo(ExState &State) { + char FName[MAXPATH]; + + strcpy(FName, FileName); + if (State.GetStrParam(View, FName, sizeof(FName)) == 0) + if (View->MView->Win->GetFile("Write To", sizeof(FName), FName, HIST_PATH, GF_SAVEAS) == 0) return 0; + return FileWriteTo(FName); +} + +int EBuffer::BlockReadX(ExState &State, int blockMode) { + char Name[MAXPATH]; + char FName[MAXPATH]; + + if (JustDirectory(FileName, FName) == -1) return 0; + SlashDir(FName); + if (State.GetStrParam(View, FName, sizeof(FName)) == 0) + if (View->MView->Win->GetFile("Read block", sizeof(FName), FName, HIST_PATH, GF_OPEN) == 0) return 0; + + if (ExpandPath(FName, Name) == -1) { + View->MView->Win->Choice(GPC_ERROR, "Error", 1, "O&K", "Invalid path: %s.", FName); + return 0; + } + return BlockReadFrom(FName, blockMode); +} + +int EBuffer::BlockRead(ExState &State) { + return BlockReadX(State, BlockMode); +} + +int EBuffer::BlockReadStream(ExState &State) { + return BlockReadX(State, bmStream); +} + +int EBuffer::BlockReadLine(ExState &State) { + return BlockReadX(State, bmLine); +} + +int EBuffer::BlockReadColumn(ExState &State) { + return BlockReadX(State, bmColumn); +} + +int EBuffer::BlockWrite(ExState &State) { + char Name[MAXPATH]; + char FName[MAXPATH]; + int Append = 0; + + if (JustDirectory(FileName, FName) == -1) return 0; + SlashDir(FName); + if (State.GetStrParam(View, FName, sizeof(FName)) == 0) + if (View->MView->Win->GetFile("Write block", sizeof(FName), FName, HIST_PATH, GF_SAVEAS) == 0) + return 0; + + if (ExpandPath(FName, Name) == -1) { + View->MView->Win->Choice(GPC_ERROR, "Error", 1, "O&K", "Invalid path: %s.", FName); + return 0; + } + if (FindFile(Name) == 0) { + if (FileExists(Name)) { + switch (View->MView->Win->Choice(GPC_ERROR, "File Exists", + 3, + "&Overwrite", + "&Append", + "&Cancel", + "%s", Name)) + { + case 0: + break; + case 1: + Append = 1; + break; + case 2: + case -1: + default: + return 0; + + } + } + } else { + View->MView->Win->Choice(GPC_ERROR, "Error", 1, "O&K", "Already editing '%s.'", Name); + return 0; + } + return BlockWriteTo(Name, Append); +} + +int EBuffer::Find(ExState &State) { + char find[MAXSEARCH+1] = ""; + char options[32] = ""; + + if (State.GetStrParam(View, find, sizeof(find)) != 0) { + if (State.GetStrParam(View, options, sizeof(options)) == 0) + strcpy(options, BFS(this, BFS_DefFindOpt)); + + LSearch.ok = 0; + strcpy(LSearch.strSearch, find); + LSearch.strReplace[0] = 0; + LSearch.Options = 0; + if (ParseSearchOptions(0, options, LSearch.Options) == 0) return 0; + LSearch.ok = 1; + } else if ((HaveGUIDialogs & GUIDLG_FIND) && GUIDialogs) { + LSearch.ok = 0; + LSearch.strSearch[0] = 0; + LSearch.strReplace[0] = 0; + LSearch.Options = 0; + if (BFS(this, BFS_DefFindOpt)) + strcpy(options, BFS(this, BFS_DefFindOpt)); + if (ParseSearchOptions(0, options, LSearch.Options) == 0) + LSearch.Options = 0; + + if (DLGGetFind(View->MView->Win, LSearch) == 0) + return 0; + } else { + if (BFS(this, BFS_DefFindOpt)) + strcpy(options, BFS(this, BFS_DefFindOpt)); + if (View->MView->Win->GetStr("Find", sizeof(find), find, HIST_SEARCH) == 0) return 0; + if (View->MView->Win->GetStr("Options (All/Block/Cur/Delln/Glob/Igncase/Joinln/Rev/Word/regX)", sizeof(options), options, HIST_SEARCHOPT) == 0) return 0; + + LSearch.ok = 0; + strcpy(LSearch.strSearch, find); + LSearch.strReplace[0] = 0; + LSearch.Options = 0; + if (ParseSearchOptions(0, options, LSearch.Options) == 0) return 0; + LSearch.ok = 1; + } + if (LSearch.ok == 0) return 0; + LSearch.Options |= SEARCH_CENTER; + if (Find(LSearch) == 0) return 0; + return 1; +} + +int EBuffer::FindReplace(ExState &State) { + char find[MAXSEARCH+1] = ""; + char replace[MAXSEARCH+1] = ""; + char options[32] = ""; + + if (State.GetStrParam(View, find, sizeof(find)) != 0) { + if (State.GetStrParam(View, replace, sizeof(replace)) == 0) + return 0; + if (State.GetStrParam(View, options, sizeof(options)) == 0) + return 0; + + LSearch.ok = 0; + strcpy(LSearch.strSearch, find); + strcpy(LSearch.strReplace, replace); + LSearch.Options = 0; + if (ParseSearchOptions(1, options, LSearch.Options) == 0) return 0; + LSearch.Options |= SEARCH_REPLACE; + LSearch.ok = 1; + } else if ((HaveGUIDialogs & GUIDLG_FINDREPLACE) && GUIDialogs) { + LSearch.ok = 0; + LSearch.strSearch[0] = 0; + LSearch.strReplace[0] = 0; + LSearch.Options = 0; + if (BFS(this, BFS_DefFindReplaceOpt)) + strcpy(options, BFS(this, BFS_DefFindReplaceOpt)); + if (ParseSearchOptions(1, options, LSearch.Options) == 0) + LSearch.Options = 0; + if (DLGGetFindReplace(View->MView->Win, LSearch) == 0) + return 0; + } else { + if (BFS(this, BFS_DefFindReplaceOpt)) + strcpy(options, BFS(this, BFS_DefFindReplaceOpt)); + if (State.GetStrParam(View, find, sizeof(find)) == 0) + if (View->MView->Win->GetStr("Find", sizeof(find), find, HIST_SEARCH) == 0) return 0; + if (State.GetStrParam(View, replace, sizeof(replace)) == 0) + if (View->MView->Win->GetStr("Replace", sizeof(replace), replace, HIST_SEARCH) == 0) return 0; + if (State.GetStrParam(View, options, sizeof(options)) == 0) + if (View->MView->Win->GetStr("Options (All/Block/Cur/Delln/Glob/Igncase/Joinln/Rev/Noask/Word/regX)", sizeof(options), options, HIST_SEARCHOPT) == 0) return 0; + + LSearch.ok = 0; + strcpy(LSearch.strSearch, find); + strcpy(LSearch.strReplace, replace); + LSearch.Options = 0; + if (ParseSearchOptions(1, options, LSearch.Options) == 0) return 0; + LSearch.Options |= SEARCH_REPLACE; + LSearch.ok = 1; + } + if (LSearch.ok == 0) return 0; + LSearch.Options |= SEARCH_CENTER; + if (Find(LSearch) == 0) return 0; + return 1; +} + +int EBuffer::FindRepeat(ExState &State) { + if (LSearch.ok == 0) return Find(State); + LSearch.Options |= SEARCH_NEXT; + LSearch.Options &= ~SEARCH_GLOBAL; + if (Find(LSearch) == 0) return 0; + return 1; +} + +int EBuffer::FindRepeatReverse(ExState &State) { + int rc; + + if (LSearch.ok == 0) return Find(State); + LSearch.Options |= SEARCH_NEXT; + LSearch.Options &= ~SEARCH_GLOBAL; + LSearch.Options ^= SEARCH_BACK; + rc = Find(LSearch); + LSearch.Options ^= SEARCH_BACK; + return rc; +} + +int EBuffer::FindRepeatOnce(ExState &State) { + if (LSearch.ok == 0) return Find(State); + LSearch.Options |= SEARCH_NEXT; + LSearch.Options &= ~SEARCH_GLOBAL; + LSearch.Options &= ~SEARCH_ALL; + if (Find(LSearch) == 0) return 0; + return 1; +} + +int EBuffer::ChangeMode(ExState &State) { + char Mode[32] = ""; + int rc; + + if (State.GetStrParam(View, Mode, sizeof(Mode)) == 0) + if (View->MView->Win->GetStr("Mode", sizeof(Mode), Mode, HIST_SETUP) == 0) return 0; + + rc = ChangeMode(Mode); + FullRedraw(); + return rc; +} + +int EBuffer::ChangeKeys(ExState &State) { + int rc; + char Mode[32] = ""; + + if (State.GetStrParam(View, Mode, sizeof(Mode)) == 0) + if (View->MView->Win->GetStr("Mode", sizeof(Mode), Mode, HIST_SETUP) == 0) return 0; + + rc = ChangeKeys(Mode); + FullRedraw(); + return rc; +} + +int EBuffer::ChangeFlags(ExState &State) { + int rc; + char Mode[32] = ""; + + if (State.GetStrParam(View, Mode, sizeof(Mode)) == 0) + if (View->MView->Win->GetStr("Mode", sizeof(Mode), Mode, HIST_SETUP) == 0) return 0; + + rc = ChangeFlags(Mode); + FullRedraw(); + return rc; +} + +int EBuffer::ChangeTabSize(ExState &State) { + int No; + + if (State.GetIntParam(View, &No) == 0) { + char Num[10]; + + sprintf(Num, "%d", BFI(this, BFI_TabSize)); + if (View->MView->Win->GetStr("TabSize", sizeof(Num), Num, HIST_SETUP) == 0) return 0; + No = atol(Num); + } + if (No < 1) return 0; + if (No > 32) return 0; + BFI(this, BFI_TabSize) = No; + FullRedraw(); + return 1; +} + +int EBuffer::SetIndentWithTabs(ExState &State) { + int No; + + if (State.GetIntParam(View, &No) == 0) return 0; + Flags.num[BFI_IndentWithTabs] = No ? 1 : 0; + return 1; +} + +int EBuffer::ChangeRightMargin(ExState &State) { + char Num[10]; + int No; + + if (State.GetIntParam(View, &No) == 0) { + sprintf(Num, "%d", BFI(this, BFI_RightMargin) + 1); + if (View->MView->Win->GetStr("RightMargin", sizeof(Num), Num, HIST_SETUP) == 0) return 0; + No = atol(Num) - 1; + } + if (No <= 1) return 0; + BFI(this, BFI_RightMargin) = No; + Msg(S_INFO, "RightMargin set to %d.", No + 1); + return 1; +} + +int EBuffer::ChangeLeftMargin(ExState &State) { + char Num[10]; + int No; + + if (State.GetIntParam(View, &No) == 0) { + sprintf(Num, "%d", BFI(this, BFI_LeftMargin) + 1); + if (View->MView->Win->GetStr("LeftMargin", sizeof(Num), Num, HIST_SETUP) == 0) return 0; + No = atol(Num) - 1; + } + if (No < 0) return 0; + BFI(this, BFI_LeftMargin) = No; + Msg(S_INFO, "LeftMargin set to %d.", No + 1); + return 1; +} + + +int EBuffer::CanQuit() { + if (Modified) + return 0; + else + return 1; +} + +int EBuffer::ConfQuit(GxView *V, int multiFile) { + if (Modified) { + if (multiFile) { + switch (V->Choice(GPC_ERROR, + "File Modified", + 5, + "&Save", + "&As", + "A&ll", + "&Discard", + "&Cancel", + "%s", FileName)) + { + case 0: /* Save */ + if (Save() == 0) return 0; + break; + case 1: /* As */ + { + char FName[MAXPATH]; + strcpy(FName, FileName); + if (V->GetFile("Save As", sizeof(FName), FName, HIST_PATH, GF_SAVEAS) == 0) return 0; + if (FileSaveAs(FName) == 0) return 0; + } + break; + case 2: /* Save all */ + return -2; + case 3: /* Discard */ + break; + case 4: /* Cancel */ + case -1: + default: + return 0; + } + }else { + switch (V->Choice(GPC_ERROR, + "File Modified", + 4, + "&Save", + "&As", + "&Discard", + "&Cancel", + "%s", FileName)) + { + case 0: /* Save */ + if (Save() == 0) return 0; + break; + case 1: /* As */ + { + char FName[MAXPATH]; + strcpy(FName, FileName); + if (V->GetFile("Save As", sizeof(FName), FName, HIST_PATH, GF_SAVEAS) == 0) return 0; + if (FileSaveAs(FName) == 0) return 0; + } + break; + case 2: /* Discard */ + break; + case 3: /* Cancel */ + case -1: + default: + return 0; + } + } + } + return 1; +} + +void EBuffer::GetName(char *AName, int MaxLen) { + strncpy(AName, FileName, MaxLen); + AName[MaxLen - 1] = 0; +} + +void EBuffer::GetPath(char *APath, int MaxLen) { + JustDirectory(FileName, APath); +} + +void EBuffer::GetInfo(char *AInfo, int MaxLen) { + sprintf(AInfo, + "%2d %04d:%03d%c%-150s ", + ModelNo, + 1 + CP.Row, 1 + CP.Col, + Modified ? '*': ' ', + FileName); +} + +void EBuffer::GetTitle(char *ATitle, int MaxLen, char *ASTitle, int SMaxLen) { + char *p; + + strncpy(ATitle, FileName, MaxLen - 1); + ATitle[MaxLen - 1] = 0; + p = SepRChr(FileName); + if (p) { + strncpy(ASTitle, p + 1, SMaxLen - 1); + ASTitle[SMaxLen - 1] = 0; + } else { + strncpy(ASTitle, FileName, SMaxLen - 1); + ASTitle[SMaxLen - 1] = 0; + } +} + +#ifdef CONFIG_I_ASCII +int EBuffer::ASCIITable(ExState &/*State*/) { + int rc; + + rc = View->MView->Win->PickASCII(); + if (rc != -1) + return InsertChar(char(rc)); + + return 0; +} +#endif + +int EBuffer::ScrollLeft(ExState &State) { + int Cols; + + if (State.GetIntParam(View, &Cols) == 0) + Cols = 8; + return ScrollLeft(Cols); +} + +int EBuffer::ScrollRight(ExState &State) { + int Cols; + + if (State.GetIntParam(View, &Cols) == 0) + Cols = 8; + return ScrollRight(Cols); +} + +int EBuffer::ScrollDown(ExState &State) { + int Rows; + + if (State.GetIntParam(View, &Rows) == 0) + Rows = 1; + return ScrollDown(Rows); +} + +int EBuffer::ScrollUp(ExState &State) { + int Rows; + + if (State.GetIntParam(View, &Rows) == 0) + Rows = 1; + return ScrollUp(Rows); +} + +#ifdef CONFIG_TAGS +int EBuffer::FindTag(ExState &State) { + char Tag[MAXSEARCH] = ""; + + if (State.GetStrParam(View, Tag, sizeof(Tag)) == 0) + if (View->MView->Win->GetStr("Find tag", sizeof(Tag), Tag, HIST_SEARCH) == 0) return 0; + + int j = 2; + while (j--) { + int i; + + i = TagFind(this, View, Tag); + if (i > 0) + return 1; + else if (j && (i < 0)) { + /* Try autoload tags */ + if (View->ExecCommand(ExTagLoad, State) == 0) + break; + } else { + Msg(S_INFO, "Tag '%s' not found.", Tag); + break; + } + } + return 0; + +} +#endif + +// these two will probably be replaced in the future +int EBuffer::InsertDate(ExState &State) { + char strArg[128] = ""; + char buf[128], *p; + + time_t t; + + time(&t); + + if (State.GetStrParam(View, strArg, sizeof(strArg))) { + struct tm *tt = localtime(&t); + strftime(buf, sizeof(buf), strArg, tt); + buf[sizeof(buf) - 1] = 0; + } else { + //** 012345678901234567890123 + //** Wed Jan 02 02:23:54 1991 + p = ctime(&t); + sprintf(buf, "%.10s %.4s", p, p + 20); + } + puts(buf); + + return InsertString(buf, strlen(buf)); +} + + +int EBuffer::InsertUid() { + char *p = getenv("USER"); + if (p == 0) p = getenv("NAME"); + if (p == 0) p = getenv("ID"); + // mostly for Windows. Why they can't just be standard, I don't know... + if (p == 0) p = getenv("USERNAME"); + if (p == 0) { + Msg(S_INFO, "User ID not set ($USER)."); + //return 0; + p = "UNKNOWN USER"; + } + return InsertString(p, strlen(p)); +} + +int EBuffer::ShowHelpWord(ExState &State) { + //** Code for BlockSelectWord to find the word under the cursor, + const char *achr = "+-_."; // these are accepted characters + char buf[128]; + int Y = VToR(CP.Row); + PELine L = RLine(Y); + int P; + + P = CharOffset(L, CP.Col); + + // fix \b for the case of CATBS + for(int i = 0; i < P; i++) { + //printf("%d - %d %d %c %c\n", i, P, L->Chars[i], + //L->Chars[i], L->Chars[P]); + if ((L->Chars[i] == '\b') && (P < (L->Count - 2))) + P += 2; + } + size_t len = 0; + if (P < L->Count) { + // To start of word, + while ((P > 0) + && ((L->Chars[P - 1] == '\b') || isalnum(L->Chars[P - 1]) + || (strchr(achr, L->Chars[P - 1]) != NULL))) + P--; // '_' for underline is hidden in achr + if ((P < (L->Count - 1)) && (L->Chars[P] == '\b')) + P++; + // To end of word, + while ((len < (sizeof(buf) - 1)) && (P < L->Count)) { + if (((P + 1) < L->Count) && (L->Chars[P + 1] == '\b')) + P += 2; + else if (isalnum(L->Chars[P]) + || (strchr(achr, L->Chars[P]) != NULL)) + buf[len++] = L->Chars[P++]; + else + break; + } + } + buf[len] = 0; + //printf("Word: %s\n", buf); + //if (buf[0] == 0) { + // Msg(INFO, "No valid word under the cursor."); + // return 0; + //} + return View->SysShowHelp(State, buf[0] ? buf : 0); +} + +int EBuffer::GetStrVar(int var, char *str, int buflen) { + assert(buflen >= 0); + if (buflen == 0) + return 0; + //puts("variable EBuffer\x7"); + switch (var) { + case mvFilePath: + //puts("variable FilePath\x7"); + strncpy(str, FileName, buflen); + str[buflen - 1] = 0; + return 1; + + case mvFileName: + JustFileName(FileName, str); + return 1; + + case mvFileDirectory: + JustDirectory(FileName, str); + return 1; + case mvFileBaseName: + { + char buf[MAXPATH]; + char *dot, *dot2; + + JustFileName(FileName, buf); + + dot = strchr(buf, '.'); + while ((dot2 = strchr(dot + 1, '.')) != NULL) + dot = dot2; + if (dot) + *dot = 0; + strcpy(str, buf); + } + return 1; + + case mvFileExtension: + { + char buf[MAXPATH]; + char *dot, *dot2; + + JustFileName(FileName, buf); + + dot = strchr(buf, '.'); + while ((dot2 = strchr(dot + 1, '.')) != NULL) + dot = dot2; + if (dot) + strcpy(str, dot); + else + str[0] = 0; + } + return 1; + + case mvChar: + case mvWord: + case mvLine: + return 0; + } + return EModel::GetStrVar(var, str, buflen); +} + +int EBuffer::GetIntVar(int var, int *value) { + switch (var) { + case mvCurRow: *value = VToR(CP.Row) + 1; return 1; + case mvCurCol: *value = CP.Col; return 1; + } + return EModel::GetIntVar(var, value); +} diff --git a/src/o_buflist.cpp b/src/o_buflist.cpp new file mode 100644 index 0000000..cbff94c --- /dev/null +++ b/src/o_buflist.cpp @@ -0,0 +1,167 @@ +/* o_buflist.cpp + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#include "fte.h" + +BufferView *BufferList = 0; + +BufferView::BufferView(int createFlags, EModel **ARoot): EList(createFlags, ARoot, "Buffers") { + ModelNo = 0; // trick + BList = 0; + BCount = 0; +} + +BufferView::~BufferView() { + if (BList) { + for (int i = 0; i < BCount; i++) + if (BList[i]) + free(BList[i]); + free(BList); + } + BufferList = 0; +} + +EEventMap *BufferView::GetEventMap() { + return FindEventMap("BUFFERS"); +} + +int BufferView::GetContext() { + return CONTEXT_BUFFERS; +} + +void BufferView::DrawLine(PCell B, int Line, int Col, ChColor color, int Width) { + if (Line < BCount) + if (Col < int(strlen(BList[Line]))) + MoveStr(B, 0, Width, BList[Line] + Col, color, Width); +} + +char* BufferView::FormatLine(int Line) { + return strdup(BList[Line]); +} + +void BufferView::UpdateList() { + EModel *B = ActiveModel; + int No; + char s[512] = ""; + + if (BList) { + for (int i = 0; i < BCount; i++) + if (BList[i]) + free(BList[i]); + free(BList); + } + BList = 0; + BCount = 0; + while (B) { + BCount++; + B = B->Next; + if (B == ActiveModel) break; + } + BList = (char **) malloc(sizeof(char *) * BCount); + assert(BList != 0); + B = ActiveModel; + No = 0; + while (B) { + B->GetInfo(s, sizeof(s) - 1); + BList[No++] = strdup(s); + B = B->Next; + if (B == ActiveModel) break; + if (No >= BCount) break; + } + Count = BCount; + NeedsUpdate = 1; +} + +EModel *BufferView::GetBufferById(int No) { + EModel *B; + + B = ActiveModel; + while (B) { + if (No == 0) { + return B; + } + No--; + B = B->Next; + if (B == ActiveModel) break; + } + return 0; +} + +int BufferView::ExecCommand(int Command, ExState &State) { + switch (Command) { + case ExCloseActivate: + { + EModel *B; + + B = GetBufferById(Row); + if (B && B != this) { + View->SwitchToModel(B); + delete this; + return ErOK; + } + } + return ErFAIL; + case ExBufListFileClose: + { + EModel *B = GetBufferById(Row); + + if (B && B != this && Count > 1) { + if (B->ConfQuit(View->MView->Win)) { + View->DeleteModel(B); + } + UpdateList(); + return ErOK; + } + } + return ErFAIL; + case ExBufListFileSave: + { + EModel *B = GetBufferById(Row); + + if (B && B->GetContext() == CONTEXT_FILE) + if (((EBuffer *)B)->Save()) + return ErOK; + } + return ErFAIL; + + case ExActivateInOtherWindow: + { + EModel *B = GetBufferById(Row); + + if (B) { + View->Next->SwitchToModel(B); + return ErOK; + } + } + return ErFAIL; + } + return EList::ExecCommand(Command, State); +} + +int BufferView::Activate(int No) { + EModel *B; + + B = GetBufferById(No); + if (B) { + View->SwitchToModel(B); + return 1; + } + return 0; +} + +void BufferView::GetInfo(char *AInfo, int MaxLen) { + sprintf(AInfo, "%2d %04d/%03d Buffers", ModelNo, Row + 1, Count); +} + +void BufferView::GetTitle(char *ATitle, int MaxLen, char *ASTitle, int SMaxLen) { + strncpy(ATitle, "Buffers", MaxLen); + ATitle[MaxLen - 1] = 0; + strncpy(ASTitle, "Buffers", SMaxLen); + ASTitle[SMaxLen - 1] = 0; +} diff --git a/src/o_buflist.h b/src/o_buflist.h new file mode 100644 index 0000000..75de5a1 --- /dev/null +++ b/src/o_buflist.h @@ -0,0 +1,32 @@ +/* o_buflist.h + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#ifndef __BUFLIST_H +#define __BUFLIST_H + +class BufferView: public EList { +public: + char **BList; + int BCount; + + BufferView(int createFlags, EModel **ARoot); + virtual ~BufferView(); + virtual EEventMap *GetEventMap(); + virtual int GetContext(); + virtual void DrawLine(PCell B, int Line, int Col, ChColor color, int Width); + virtual char* FormatLine(int Line); + virtual void UpdateList(); + EModel *GetBufferById(int No); + virtual int ExecCommand(int Command, ExState &State); + virtual int Activate(int No); + virtual void GetInfo(char *AInfo, int MaxLen); + virtual void GetTitle(char *ATitle, int MaxLen, char *ASTitle, int SMaxLen); +}; + +#endif diff --git a/src/o_directory.cpp b/src/o_directory.cpp new file mode 100644 index 0000000..a4537e0 --- /dev/null +++ b/src/o_directory.cpp @@ -0,0 +1,454 @@ +/* o_directory.cpp + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#define NEED_LOG_H +#include "fte.h" + +#ifdef CONFIG_OBJ_DIRECTORY +EDirectory::EDirectory(int createFlags, EModel **ARoot, char *aPath): EList(createFlags, ARoot, aPath) { + char XPath[MAXPATH]; + + Files = 0; + FCount = 0; + SearchLen = 0; + ExpandPath(aPath, XPath); + Slash(XPath, 1); + Path = strdup(XPath); + RescanList(); +} + +EDirectory::~EDirectory() { + if (Files) { + for (int i = 0; i < FCount; i++) + delete Files[i]; + free(Files); + } + free(Path); +} + +EEventMap *EDirectory::GetEventMap() { + return FindEventMap("DIRECTORY"); +} + +void EDirectory::DrawLine(PCell B, int Line, int Col, ChColor color, int Width) { + char s[1024]; + + MoveCh(B, ' ', color, Width); + if (Files && Line >= 0 && Line < FCount) { + int Year, Mon, Day, Hour, Min, Sec; + struct tm *t; + time_t tim; + + tim = Files[Line]->MTime(); + t = localtime(&tim); + + if (t) { + Year = t->tm_year + 1900; + Mon = t->tm_mon + 1; + Day = t->tm_mday; + Hour = t->tm_hour; + Min = t->tm_min; + Sec = t->tm_sec; + } else { + Year = Mon = Day = Hour = Min = Sec = 0; + } + + sprintf(s, + " %04d/%02d/%02d %02d:%02d:%02d %8ld ", + Year, Mon, Day, Hour, Min, Sec, + Files[Line]->Size()); + + + strcat(s, Files[Line]->Name()); + s[strlen(s) + 1] = '\0'; + s[strlen(s)] = (Files[Line]->Type() == fiDIRECTORY)? SLASH : ' '; + + if (Col < int(strlen(s))) + MoveStr(B, 0, Width, s + Col, + (Files[Line]->Type() == fiDIRECTORY) ? + (TAttr)(color | (1<<3)) : (TAttr)color, Width); + } +} + +int _LNK_CONV FileNameCmp(const void *a, const void *b) { + FileInfo *A = *(FileInfo **)a; + FileInfo *B = *(FileInfo **)b; + + if (!(A->Type() == fiDIRECTORY) && (B->Type() == fiDIRECTORY)) + return 1; + + if ((A->Type() == fiDIRECTORY) && !(B->Type() == fiDIRECTORY)) + return -1; + + return filecmp(A->Name(), B->Name()); +} + +void EDirectory::RescanList() { + char Dir[256]; + char Name[256]; + int DirCount = 0; + int SizeCount = 0; + FileFind *ff; + FileInfo *fi; + int rc; + + if (Files) + FreeList(); + + Count = 0; + FCount = 0; + if (JustDirectory(Path, Dir) != 0) return; + JustFileName(Path, Name); + + ff = new FileFind(Dir, "*", ffDIRECTORY | ffHIDDEN); + if (ff == 0) + return ; + + rc = ff->FindFirst(&fi); + while (rc == 0) { + assert(fi != 0); + if (strcmp(fi->Name(), ".") != 0) { + Files = (FileInfo **)realloc((void *)Files, ((FCount | 255) + 1) * sizeof(FileInfo *)); + if (Files == 0) + { + delete fi; + delete ff; + return; + } + + Files[FCount] = fi; + + SizeCount += Files[FCount]->Size(); + if (fi->Type() == fiDIRECTORY && (strcmp(fi->Name(), "..") != 0)) + DirCount++; + Count++; + FCount++; + } else + delete fi; + rc = ff->FindNext(&fi); + } + delete ff; + + { + char CTitle[256]; + + sprintf(CTitle, "%d files%c%d dirs%c%d bytes%c%-200.200s", + FCount, ConGetDrawChar(DCH_V), + DirCount, ConGetDrawChar(DCH_V), + SizeCount, ConGetDrawChar(DCH_V), + Dir); + SetTitle(CTitle); + } + qsort(Files, FCount, sizeof(FileInfo *), FileNameCmp); + NeedsRedraw = 1; +} + +void EDirectory::FreeList() { + if (Files) { + for (int i = 0; i < FCount; i++) + delete Files[i]; + free(Files); + } + Files = 0; + FCount = 0; +} + +int EDirectory::isDir(int No) { + char FilePath[256]; + + JustDirectory(Path, FilePath); + Slash(FilePath, 1); + strcat(FilePath, Files[No]->Name()); + return IsDirectory(FilePath); +} + +int EDirectory::ExecCommand(int Command, ExState &State) { + switch (Command) { + case ExActivateInOtherWindow: + SearchLen = 0; + Msg(S_INFO, ""); + if (Files && Row >= 0 && Row < FCount) { + if (isDir(Row)) { + } else { + return FmLoad(Files[Row]->Name(), View->Next); + } + } + return ErFAIL; + + case ExRescan: + if (RescanDir() == 0) + return ErFAIL; + return ErOK; + + case ExDirGoUp: + SearchLen = 0; + Msg(S_INFO, ""); + FmChDir(SDOT SDOT); + return ErOK; + + case ExDirGoDown: + SearchLen = 0; + Msg(S_INFO, ""); + if (Files && Row >= 0 && Row < FCount) { + if (isDir(Row)) { + FmChDir(Files[Row]->Name()); + return ErOK; + } + } + return ErFAIL; + + case ExDirGoto: + SearchLen = 0; + Msg(S_INFO, ""); + return ChangeDir(State); + + case ExDirGoRoot: + SearchLen = 0; + Msg(S_INFO, ""); + FmChDir(SSLASH); + return ErOK; + + case ExDeleteFile: + SearchLen = 0; + Msg(S_INFO, ""); + return FmRmDir(Files[Row]->Name()); + } + return EList::ExecCommand(Command, State); +} + +int EDirectory::Activate(int No) { + SearchLen = 0; + Msg(S_INFO, ""); + if (Files && No >= 0 && No < FCount) { + if (isDir(No)) { + FmChDir(Files[No]->Name()); + return 0; + } else { + return FmLoad(Files[No]->Name(), View); + } + } + return 1; +} + +void EDirectory::HandleEvent(TEvent &Event) { + STARTFUNC("EDirectory::HandleEvent"); + int resetSearch = 0; + EModel::HandleEvent(Event); + switch (Event.What) { + case evKeyDown: + LOG << "Key Code: " << kbCode(Event.Key.Code) << ENDLINE; + resetSearch = 1; + switch (kbCode(Event.Key.Code)) { + case kbBackSp: + LOG << "Got backspace" << ENDLINE; + resetSearch = 0; + if (SearchLen > 0) { + SearchName[--SearchLen] = 0; + Row = SearchPos[SearchLen]; + Msg(S_INFO, "Search: [%s]", SearchName); + } else + Msg(S_INFO, ""); + break; + case kbEsc: + Msg(S_INFO, ""); + break; + default: + resetSearch = 0; // moved here - its better for user + // otherwice there is no way to find files like i_ascii + if (isAscii(Event.Key.Code) && (SearchLen < MAXISEARCH)) { + char Ch = (char) Event.Key.Code; + int Found; + + LOG << " -> " << BinChar(Ch) << ENDLINE; + + SearchPos[SearchLen] = Row; + SearchName[SearchLen] = Ch; + SearchName[++SearchLen] = 0; + Found = 0; + LOG << "Comparing " << SearchName << ENDLINE; + for (int i = Row; i < FCount; i++) { + LOG << " to -> " << Files[i]->Name() << ENDLINE; + if (strnicmp(SearchName, Files[i]->Name(), SearchLen) == 0) { + Row = i; + Found = 1; + break; + } + } + if (Found == 0) + SearchName[--SearchLen] = 0; + Msg(S_INFO, "Search: [%s]", SearchName); + } + break; + } + } + if (resetSearch) { + SearchLen = 0; + } + LOG << "SearchLen = " << SearchLen << ENDLINE; +} + +int EDirectory::RescanDir() { + char CName[256] = ""; + + if (Row >= 0 && Row < FCount) + strcpy(CName, Files[Row]->Name()); + Row = 0; + RescanList(); + if (CName[0] != 0) { + for (int i = 0; i < FCount; i++) { + if (filecmp(Files[i]->Name(), CName) == 0) + { + Row = i; + break; + } + } + } + return 1; +} + +int EDirectory::FmChDir(const char *Name) { + char Dir[256]; + char CName[256] = ""; + + if (strcmp(Name, SSLASH) == 0) { + JustRoot(Path, Dir); + } else if (strcmp(Name, SDOT SDOT) == 0) { + Slash(Path, 0); + JustFileName(Path, CName); + JustDirectory(Path, Dir); + } else { + JustDirectory(Path, Dir); + Slash(Dir, 1); + strcat(Dir, Name); + } + Slash(Dir, 1); + free(Path); + Path = strdup(Dir); + Row = 0; + RescanList(); + if (CName[0] != 0) { + for (int i = 0; i < FCount; i++) { + if (filecmp(Files[i]->Name(), CName) == 0) + { + Row = i; + break; + } + } + } + UpdateTitle(); + return 1; +} + +int EDirectory::FmRmDir(char const* Name) +{ + char FilePath[256]; + strcpy(FilePath, Path); + Slash(FilePath, 1); + strcat(FilePath, Name); + + int choice = + View->MView->Win->Choice(GPC_CONFIRM, + "Remove File", + 2, "O&K", "&Cancel", + "Remove %s?", Name); + + if (choice == 0) + { + if (unlink(FilePath) == 0) + { + // put the cursor to the previous row + --Row; + + // There has to be a more efficient way of doing this ... + return RescanDir(); + } + else + { + Msg(S_INFO, "Failed to remove %s", Name); + return 0; + } + } + else + { + Msg(S_INFO, "Cancelled"); + return 0; + } +} + +int EDirectory::FmLoad(char *Name, EView *XView) { + char FilePath[256]; + + JustDirectory(Path, FilePath); + Slash(FilePath, 1); + strcat(FilePath, Name); + return FileLoad(0, FilePath, NULL, XView); +} + +void EDirectory::GetName(char *AName, int MaxLen) { + strncpy(AName, Path, MaxLen); + AName[MaxLen - 1] = 0; + Slash(AName, 0); +} + +void EDirectory::GetPath(char *APath, int MaxLen) { + strncpy(APath, Path, MaxLen); + APath[MaxLen - 1] = 0; + Slash(APath, 0); +} + +void EDirectory::GetInfo(char *AInfo, int MaxLen) { + sprintf(AInfo, + "%2d %04d/%03d %-150s", + ModelNo, + Row + 1, FCount, + Path); +} + +void EDirectory::GetTitle(char *ATitle, int MaxLen, char *ASTitle, int SMaxLen) { + + strncpy(ATitle, Path, MaxLen - 1); + ATitle[MaxLen - 1] = 0; + + { + char P[MAXPATH]; + strcpy(P, Path); + Slash(P, 0); + + JustDirectory(P, ASTitle); + Slash(ASTitle, 1); + } +} + +int EDirectory::ChangeDir(ExState &State) { + char Dir[MAXPATH]; + char Dir2[MAXPATH]; + + if (State.GetStrParam(View, Dir, sizeof(Dir)) == 0) { + strcpy(Dir, Path); + if (View->MView->Win->GetStr("Set directory", sizeof(Dir), Dir, HIST_PATH) == 0) + return 0; + } + if (ExpandPath(Dir, Dir2) == -1) + return 0; +#if 0 + // is this needed for other systems as well ? + Slash(Dir2, 1); +#endif + if (Path) + free(Path); + Path = strdup(Dir2); + Row = -1; + UpdateTitle(); + return RescanDir(); +} + +int EDirectory::GetContext() { return CONTEXT_DIRECTORY; } +char *EDirectory::FormatLine(int Line) { return 0; }; +int EDirectory::CanActivate(int Line) { return 1; } +#endif diff --git a/src/o_directory.h b/src/o_directory.h new file mode 100644 index 0000000..b025c4d --- /dev/null +++ b/src/o_directory.h @@ -0,0 +1,55 @@ +/* o_directory.h + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#ifndef __ODIRECTORY_H +#define __ODIRECTORY_H + +#ifdef CONFIG_OBJ_DIRECTORY + +class EDirectory: public EList { +public: + char *Path; + FileInfo **Files; + int FCount; + int SearchLen; + char SearchName[MAXISEARCH]; + int SearchPos[MAXISEARCH]; + + EDirectory(int createFlags, EModel **ARoot, char *aPath); + virtual ~EDirectory(); + + virtual int GetContext(); + virtual EEventMap *GetEventMap(); + virtual int ExecCommand(int Command, ExState &State); + virtual void HandleEvent(TEvent &Event); + + virtual void DrawLine(PCell B, int Line, int Col, ChColor color, int Width); + virtual char *FormatLine(int Line); + + virtual void RescanList(); +// virtual void UpdateList(); + virtual void FreeList(); + virtual int CanActivate(int Line); + virtual int Activate(int No); + + virtual void GetName(char *AName, int MaxLen); + virtual void GetPath(char *APath, int MaxLen); + virtual void GetInfo(char *AInfo, int MaxLen); + virtual void GetTitle(char *ATitle, int MaxLen, char *ASTitle, int SMaxLen); + + int isDir(int No); + int FmChDir(const char *Name); + int FmLoad(char *Name, EView *View); + int FmRmDir(char const* Name); + int ChangeDir(ExState &State); + int RescanDir(); +}; +#endif + +#endif diff --git a/src/o_list.cpp b/src/o_list.cpp new file mode 100644 index 0000000..566fd7a --- /dev/null +++ b/src/o_list.cpp @@ -0,0 +1,623 @@ +/* o_list.cpp + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#include "fte.h" + +EListPort::EListPort(EList *L, EView *V): EViewPort(V) { + List = L; + OldTopRow = OldLeftCol = OldRow = OldCount = -1; + GetPos(); +} + +EListPort::~EListPort() { + StorePos(); +} + +void EListPort::StorePos() { + List->Row = Row; + List->TopRow = TopRow; + List->LeftCol = LeftCol; + List->NeedsUpdate = 1; +} + +void EListPort::GetPos() { + Row = List->Row; + TopRow = List->TopRow; + LeftCol = List->LeftCol; +} + +void EListPort::HandleEvent(TEvent &Event) { + int W = 1; + int H = 1; + + EViewPort::HandleEvent(Event); + + if (View && View->MView && View->MView->Win) { + View->MView->ConQuerySize(&W, &H); + H--; + } + + switch (Event.What) { + case evCommand: + switch (Event.Msg.Command) { + case cmVScrollUp: + List->ScrollDown(1); + Event.What = evNone; + break; + case cmVScrollDown: + List->ScrollUp(1); + Event.What = evNone; + break; + case cmVScrollPgUp: + List->MovePageUp(); + Event.What = evNone; + break; + case cmVScrollPgDn: + List->MovePageDown(); + Event.What = evNone; + break; + case cmVScrollMove: + { + int ypos; + + ypos = List->Row - List->TopRow; + List->TopRow = Event.Msg.Param1; + List->Row = List->TopRow + ypos; + } + Event.What = evNone; + break; + case cmHScrollLeft: + List->ScrollRight(1); + Event.What = evNone; + break; + case cmHScrollRight: + List->ScrollLeft(1); + Event.What = evNone; + break; + case cmHScrollPgLt: + List->ScrollRight(W); + Event.What = evNone; + break; + case cmHScrollPgRt: + List->ScrollLeft(W); + Event.What = evNone; + break; + case cmHScrollMove: + List->LeftCol = Event.Msg.Param1; + Event.What = evNone; + break; + } + break; + case evMouseDown: + case evMouseUp: + case evMouseMove: + case evMouseAuto: + HandleMouse(Event); + break; + } +} + +void EListPort::HandleMouse(TEvent &Event) { + int W, H; + int x, y, xx, yy; + + View->MView->ConQuerySize(&W, &H); + + x = Event.Mouse.X; + y = Event.Mouse.Y; + yy = y + TopRow; + xx = x + LeftCol; +// if (yy >= Selected) yy = Window->Buffer->VCount - 1; + if (yy < 0) yy = 0; + if (xx < 0) xx = 0; + + switch (Event.What) { + case evMouseDown: + if (Event.Mouse.Y == H - 1) + break; + if (View->MView->Win->CaptureMouse(1)) + View->MView->MouseCaptured = 1; + else + break; + + if (Event.Mouse.Buttons == 1) + if (yy < List->Count && yy >= 0) { + List->SetPos(yy, LeftCol); + if (Event.Mouse.Count == 2) { + if (List->CanActivate(List->Row)) { + View->MView->Win->CaptureMouse(0); + if (List->Activate() == 1) { + //View->MView->EndExec(1); + } + } + } + } + if (Event.Mouse.Buttons == 2) + if (yy < List->Count && yy >= 0) + List->SetPos(yy, LeftCol); + Event.What = evNone; + break; + case evMouseAuto: + case evMouseMove: + if (View->MView->MouseCaptured) { + if (Event.Mouse.Buttons == 1 || Event.Mouse.Buttons == 2) + if (yy < List->Count && yy >= 0) { + List->SetPos(yy, LeftCol); + } + Event.What = evNone; + } + break; + case evMouseUp: + if (View->MView->MouseCaptured) + View->MView->Win->CaptureMouse(0); + else + break; + if (Event.Mouse.Buttons == 2) { + EEventMap *Map = View->MView->Win->GetEventMap(); + const char *MName = 0; + + if (yy < List->Count && yy >= 0) { + List->SetPos(yy, LeftCol); + } + + if (Map) + MName = Map->GetMenu(EM_LocalMenu); + if (MName == 0) + MName = "Local"; + View->MView->Win->Parent->PopupMenu(MName); + } + View->MView->MouseCaptured = 0; + Event.What = evNone; + break; + } +} + +void EListPort::UpdateView() { + if (OldLeftCol != LeftCol || OldTopRow != TopRow || OldCount != List->Count) + List->NeedsRedraw = List->NeedsUpdate = 1; + + if (List->NeedsUpdate) { + + List->UpdateList(); + + List->FixPos(); + + if (List->View == View) + GetPos(); + + if (OldLeftCol != LeftCol || OldTopRow != TopRow || OldCount != List->Count) + List->NeedsRedraw = List->NeedsUpdate = 1; + + PaintView(List->NeedsRedraw); + OldRow = Row; + OldTopRow = TopRow; + OldLeftCol = LeftCol; + OldCount = List->Count; + List->NeedsUpdate = 0; + List->NeedsRedraw = 0; + } +} + +void EListPort::RepaintView() { + PaintView(1); + OldRow = Row; + OldTopRow = TopRow; + OldLeftCol = LeftCol; + OldCount = List->Count; + List->NeedsUpdate = 0; + List->NeedsRedraw = 0; +} + +void EListPort::PaintView(int PaintAll) { + TDrawBuffer B; + int I; + ChColor color; + int W, H; + + if (List->NeedsRedraw) + PaintAll = 1; + + if (View == 0 || View->MView == 0 || View->MView->Win == 0) + return ; + + View->MView->ConQuerySize(&W, &H); + H--; + + if (View->MView->Win->GetViewContext() != View->MView) + return; + for (I = 0; I < H; I++) { + if (PaintAll || I + TopRow == Row || I + TopRow == OldRow) { + color = ((Row == I + TopRow) && View->MView->Win->IsActive()) + ? hcList_Selected : hcList_Normal; + MoveChar(B, 0, W, ' ', color, W); + if (I + TopRow < List->Count) + List->DrawLine(B, I + TopRow, LeftCol, color, W); + View->MView->ConPutBox(0, I, W, 1, B); + } + } +} + +void EListPort::UpdateStatus() { + RepaintStatus(); +} + +void EListPort::RepaintStatus() { + TDrawBuffer B; + char s[80]; + int W, H; + char SColor; + + if (View == 0 || View->MView == 0 || View->MView->Win == 0) + return ; + + View->MView->ConQuerySize(&W, &H); + + List->UpdateList(); + + List->FixPos(); + + if (List->View == View) + GetPos(); + + if (View->MView->Win->GetStatusContext() != View->MView) + return; + + View->MView->Win->SetSbVPos(TopRow, H, List->Count + (WeirdScroll ? H - 1 : 0)); + View->MView->Win->SetSbHPos(LeftCol, W, 1024 + (WeirdScroll ? W - 1 : 0)); + + if (View->MView->IsActive()) // hack + SColor = hcStatus_Active; + else + SColor = hcStatus_Normal; + MoveCh(B, ' ', SColor, W); + if (View->CurMsg == 0) { + if (List->Title) + MoveStr(B, 0, W, List->Title, SColor, W); + sprintf(s, "%c%d/%d", ConGetDrawChar(DCH_V), Row + 1, List->Count); + MoveStr(B, W - strlen(s), W, s, SColor, W); + } else { + MoveStr(B, 0, W, View->CurMsg, SColor, W); + } + View->MView->ConPutBox(0, H - 1, W, 1, B); + + if (View->MView->Win->GetStatusContext() == View->MView && + View->MView->Win->IsActive()) + View->MView->Win->ConSetCursorPos(0, Row - TopRow); +} + +EList::EList(int createFlags, EModel **ARoot, const char *aTitle): EModel(createFlags, ARoot) { + Title = strdup(aTitle); + Row = TopRow = Count = LeftCol = 0; + NeedsUpdate = 1; + NeedsRedraw = 1; + MouseMoved = 0; + MouseCaptured = 0; +} + +EList::~EList() { + free(Title); +} + +EViewPort *EList::CreateViewPort(EView *V) { + V->Port = new EListPort(this, V); + AddView(V); + + return V->Port; +} + +EListPort *EList::GetViewVPort(EView *V) { + return (EListPort *)V->Port; +} +EListPort *EList::GetVPort() { + return (EListPort *)View->Port; +} + +void EList::SetTitle(char *ATitle) { + if (Title) + free(Title); + Title = strdup(ATitle); + if (View && View->MView) + View->MView->RepaintStatus(); +} + + +int EList::ExecCommand(int Command, ExState &State) { + int W = 1; + int H = 1; + + if (View && View->MView && View->MView->Win) { + View->MView->ConQuerySize(&W, &H); + H--; + } + FixPos(); + switch (Command) { + case ExMoveLeft: return MoveLeft(); + case ExMoveRight: return MoveRight(); + case ExMoveUp: return MoveUp(); + case ExMoveDown: return MoveDown(); + case ExMovePageUp: return MovePageUp(); + case ExMovePageDown: return MovePageDown(); + case ExScrollLeft: return ScrollLeft(8); + case ExScrollRight: return ScrollRight(8); + case ExMovePageStart: return MovePageStart(); + case ExMovePageEnd: return MovePageEnd(); + case ExMoveFileStart: return MoveFileStart(); + case ExMoveFileEnd: return MoveFileEnd(); + case ExMoveLineStart: return MoveLineStart(); + case ExMoveLineEnd: return MoveLineEnd(); + case ExRescan: RescanList(); return ErOK; + case ExActivate: return Activate(); + } + return EModel::ExecCommand(Command, State); +} + +EEventMap *EList::GetEventMap() { + return FindEventMap("LIST"); +} + +void EList::HandleEvent(TEvent &/*Event*/) { +} + +void EList::DrawLine(PCell /*B*/, int /*Line*/, int /*Col*/, ChColor /*color*/, int /*Width*/) { +} + +char *EList::FormatLine(int /*Line*/) { + return 0; +} + +void EList::RescanList() {} +void EList::UpdateList() { NeedsUpdate = 1; } +void EList::FreeList() {} + +void EList::FixPos() { + int W, H; + int OTopRow = TopRow; + int OLeftCol = LeftCol; + int ORow = Row; + + if (View == 0 || View->MView == 0 || View->MView->Win == 0) + return ; + + View->MView->Win->ConQuerySize(&W, &H); + H--; + + //int scrollJumpX = Min(ScrollJumpX, W / 2); + int scrollJumpY = Min(ScrollJumpY, H / 2); + //int scrollBorderX = Min(ScrollBorderX, W / 2); + int scrollBorderY = Min(ScrollBorderY, H / 2); + + if (LeftCol < 0) LeftCol = 0; + if (Row >= Count) Row = Count - 1; + if (!WeirdScroll) + if (TopRow + H > Count) TopRow = Count - H; + if (Row < 0) Row = 0; + + if (GetVPort()->ReCenter) { + TopRow = Row - H / 2; + GetVPort()->ReCenter = 0; + } + if (TopRow + scrollBorderY > Row) TopRow = Row - scrollJumpY + 1 - scrollBorderY; + if (TopRow + H - scrollBorderY <= Row) TopRow = Row - H + 1 + scrollJumpY - 1 + scrollBorderY; + if (TopRow < 0) TopRow = 0; + + if (OTopRow != TopRow || OLeftCol != LeftCol || ORow != Row) { + NeedsRedraw = 1; + NeedsUpdate = 1; + } +} + +int EList::GetContext() { return CONTEXT_LIST; }; +int EList::BeginMacro() { return 1; } +int EList::CanActivate(int /*Line*/) { return 1; } +int EList::Activate(int /*No*/) { return 0; } + +int EList::SetPos(int ARow, int ACol) { + Row = ARow; + LeftCol = ACol; + NeedsUpdate = 1; + return ErOK; +} + +int EList::MoveLeft() { + if (LeftCol == 0) + return ErFAIL; + LeftCol--; + NeedsUpdate = 1; + return ErOK; +} + +int EList::MoveRight() { + LeftCol++; + NeedsUpdate = 1; + return ErOK; +} + +int EList::MoveUp() { + if (Row == 0) + return ErFAIL; + Row--; + NeedsUpdate = 1; + return ErOK; +} + +int EList::MoveDown() { + if (Row == Count - 1) + return ErFAIL; + Row++; + NeedsUpdate = 1; + return ErOK; +} + +int EList::MoveLineStart() { + if (LeftCol != 0) { + NeedsUpdate = 1; + LeftCol = 0; + } + return ErOK; +} + +int EList::MoveLineEnd() { + int W, H; + + View->MView->Win->ConQuerySize(&W, &H); + H--; + if (LeftCol != H / 2) { + LeftCol = H / 2; + NeedsUpdate = 1; + } + return ErOK; +} + +int EList::MovePageUp() { + int W, H; + + if (Row == 0) + return ErFAIL; + + View->MView->Win->ConQuerySize(&W, &H); + H--; + + Row -= H; + TopRow -= H; + if (Row < 0) + Row = 0; + if (TopRow < 0) + TopRow = 0; + NeedsUpdate = 1; + return ErOK; +} + +int EList::MovePageDown() { + int W, H; + + if (Row == Count - 1) + return ErFAIL; + + View->MView->Win->ConQuerySize(&W, &H); + H--; + + Row += H; + TopRow += H; + if (Row >= Count) + Row = Count - 1; + if (TopRow > Row) + TopRow = Row; + if (Row < 0) + Row = 0; + if (TopRow < 0) + TopRow = 0; + NeedsUpdate = 1; + return ErOK; +} + +int EList::ScrollRight(int Cols) { + if (LeftCol >= Cols) { + LeftCol -= Cols; + NeedsUpdate = 1; + } else if (LeftCol != 0) { + LeftCol = 0; + NeedsUpdate = 1; + } else + return ErFAIL; + return ErOK; +} + +int EList::ScrollLeft(int Cols) { + LeftCol += Cols; + NeedsUpdate = 1; + return ErOK; +} + +int EList::ScrollUp(int Rows) { + if (TopRow == Count - 1) + return ErFAIL; + + TopRow += Rows; + Row += Rows; + + if (Row >= Count) + Row = Count - 1; + if (Row < 0) + Row = 0; + if (TopRow > Row) + TopRow = Row; + NeedsUpdate = 1; + return ErOK; +} + +int EList::ScrollDown(int Rows) { + if (TopRow == 0) + return ErFAIL; + + TopRow -= Rows; + Row -= Rows; + + if (Row < 0) + Row = 0; + if (TopRow < 0) + TopRow = 0; + NeedsUpdate = 1; + return ErOK; +} + +int EList::MovePageStart() { + if (Row <= TopRow) + return ErFAIL; + Row = TopRow; + NeedsUpdate = 1; + return ErOK; +} + +int EList::MovePageEnd() { + int W, H; + + if (Row == Count - 1) + return ErOK; + + View->MView->Win->ConQuerySize(&W, &H); + H--; + if (Row == TopRow + H - 1) + return ErOK; + + Row = TopRow + H - 1; + if (Row >= Count) + Row = Count - 1; + if (Row < 0) + Row = 0; + NeedsUpdate = 1; + return ErOK; +} + +int EList::MoveFileStart() { + if (Row == 0 && LeftCol == 0) + return ErOK; + Row = 0; + LeftCol = 0; + NeedsUpdate = 1; + return ErOK; +} + +int EList::MoveFileEnd() { + if (Row == Count - 1 && LeftCol == 0) + return 0; + Row = Count - 1; + if (Row < 0) + Row = 0; + NeedsUpdate = 1; + LeftCol = 0; + return ErOK; +} + +int EList::Activate() { + if (Count > 0) + if (CanActivate(Row)) + if (Activate(Row) == 1) + return ErOK; + return ErFAIL; +} diff --git a/src/o_list.h b/src/o_list.h new file mode 100644 index 0000000..3d9b04c --- /dev/null +++ b/src/o_list.h @@ -0,0 +1,94 @@ +/* o_list.h + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#ifndef __OLIST_H__ +#define __OLIST_H__ + +class EList; + +class EListPort: public EViewPort { +public: + EList *List; + int Row, TopRow, LeftCol; + int OldRow, OldTopRow, OldLeftCol, OldCount; + EListPort(EList *L, EView *V); + virtual ~EListPort(); + + void StorePos(); + void GetPos(); + + virtual void HandleEvent(TEvent &Event); + virtual void HandleMouse(TEvent &Event); + + void PaintView(int PaintAll); + + virtual void UpdateView(); + virtual void RepaintView(); + virtual void UpdateStatus(); + virtual void RepaintStatus(); +}; + +class EList: public EModel { +public: + char *Title; + int Row, LeftCol, TopRow, Count; + int MouseCaptured; + int MouseMoved; + int NeedsUpdate, NeedsRedraw; + + EList(int createFlags, EModel **ARoot, const char *aTitle); + virtual ~EList(); + + virtual EViewPort *CreateViewPort(EView *V); + EListPort *GetViewVPort(EView *V); + EListPort *GetVPort(); + + void SetTitle(char *ATitle); + + virtual int ExecCommand(int Command, ExState &State); + virtual EEventMap *GetEventMap(); + virtual int GetContext(); + virtual int BeginMacro(); + void HandleEvent(TEvent &Event); + + + virtual void DrawLine(PCell B, int Line, int Col, ChColor color, int Width); + virtual char *FormatLine(int Line); + + int SetPos(int ARow, int ACol); + void FixPos(); + + virtual void RescanList(); + virtual void UpdateList(); + virtual void FreeList(); + virtual int CanActivate(int Line); + virtual int Activate(int No); + + int MoveLeft(); + int MoveRight(); + int MoveUp(); + int MoveDown(); + int MoveLineStart(); + int MoveLineEnd(); + int MovePageUp(); + int MovePageDown(); + int ScrollLeft(int Cols); + int ScrollRight(int Cols); + int ScrollUp(int Rows); + int ScrollDown(int Rows); + int MovePageStart(); + int MovePageEnd(); + int MoveFileStart(); + int MoveFileEnd(); + int Activate(); + + int UpdateRows(int minim, int maxim); +}; + +#endif diff --git a/src/o_messages.cpp b/src/o_messages.cpp new file mode 100644 index 0000000..dbe6796 --- /dev/null +++ b/src/o_messages.cpp @@ -0,0 +1,632 @@ +/* o_messages.cpp + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#include "fte.h" + +#ifdef CONFIG_OBJ_MESSAGES +#define MAXREGEXP 32 + +EMessages *CompilerMsgs = 0; + +int NCRegexp = 0; +struct { + int RefFile; + int RefLine; + int RefMsg; + RxNode *rx; +} CRegexp[MAXREGEXP]; + +int AddCRegexp(int file, int line, int msg, const char *regexp) { + if (NCRegexp >= MAXREGEXP) return 0; + CRegexp[NCRegexp].RefFile = file; + CRegexp[NCRegexp].RefLine = line; + CRegexp[NCRegexp].RefMsg = msg; + if ((CRegexp[NCRegexp].rx = RxCompile(regexp)) == NULL) { + return 0; + } + NCRegexp++; + return 1; +} + +void FreeCRegexp() +{ + while(NCRegexp--) + { + RxFree(CRegexp[NCRegexp].rx); + } +} + +EMessages::EMessages(int createFlags, EModel **ARoot, char *ADir, char *ACommand): EList(createFlags, ARoot, "Messages") { + CompilerMsgs = this; + ErrCount = 0; + ErrList = 0; + Running = 0; + BufLen = 0; + BufPos = 0; + Command = 0; + Directory = 0; + MatchCount = 0; + ReturnCode = -1; + Running = 1; + curr_dir = 0; + RunPipe(ADir, ACommand); +} + +EMessages::~EMessages() { + gui->ClosePipe(PipeId); + FreeErrors(); + free(Command); + free(Directory); + CompilerMsgs = 0; + freeDirStack(); +} + +void EMessages::freeDirStack() +{ + while(curr_dir != 0) + { + aDir *a = curr_dir; + curr_dir = curr_dir->next; + free(a->name); + delete a; + } +} + +void EMessages::NotifyDelete(EModel *Deleting) { + for (int i = 0; i < ErrCount; i++) { + if (ErrList[i]->Buf == Deleting) { + /* NOT NEEDED! + char bk[16]; + sprintf(bk, "_MSG.%d", i); + ((EBuffer *)Deleting)->RemoveBookmark(bk); + */ + ErrList[i]->Buf = 0; + } + } +} + +void EMessages::FindErrorFiles() { + for (int i = 0; i < ErrCount; i++) + if (ErrList[i]->Buf == 0 && ErrList[i]->file != 0) + FindErrorFile(i); +} + +void EMessages::FindErrorFile(int err) { + assert(err >= 0 && err < ErrCount); + if (ErrList[err]->file == 0) + return ; + + EBuffer *B; + + ErrList[err]->Buf = 0; + + B = FindFile(ErrList[err]->file); + if (B == 0) + return ; + + if (B->Loaded == 0) + return; + + AddFileError(B, err); +} + +void EMessages::AddFileError(EBuffer *B, int err) { + char bk[16]; + EPoint P; + + assert(err >= 0 && err < ErrCount); + + sprintf(bk, "_MSG.%d", err); + P.Col = 0; + P.Row = ErrList[err]->line - 1; // offset 0 + + + if (P.Row >= B->RCount) + P.Row = B->RCount - 1; + if (P.Row < 0) + P.Row = 0; + + if (B->PlaceBookmark(bk, P) == 1) + ErrList[err]->Buf = B; +} + +void EMessages::FindFileErrors(EBuffer *B) { + for (int i = 0; i < ErrCount; i++) + if (ErrList[i]->Buf == 0 && ErrList[i]->file != 0) { + if (filecmp(B->FileName, ErrList[i]->file) == 0) { + AddFileError(B, i); + } + } +} + +int EMessages::RunPipe(char *ADir, char *ACommand) { + if (!KeepMessages) + FreeErrors(); + + free(Command); + free(Directory); + + Command = strdup(ACommand); + Directory = strdup(ADir); + + MatchCount = 0; + ReturnCode = -1; + Running = 1; + BufLen = BufPos = 0; + Row = ErrCount - 1; + + { + char s[2 * MAXPATH * 4]; + + sprintf(s, "[running '%s' in '%s']", Command, Directory); + AddError(0, -1, 0, s); + } + + { + char s[MAXPATH * 2]; + sprintf(s, "Messages [%s]: %s", Directory, Command); + SetTitle(s); + } + + ChangeDir(Directory); + PipeId = gui->OpenPipe(Command, this); + return 0; +} + +EEventMap *EMessages::GetEventMap() { + return FindEventMap("MESSAGES"); +} + +int EMessages::ExecCommand(int Command, ExState &State) { + switch (Command) { + case ExChildClose: + if (Running == 0 || PipeId == -1) + break; + ReturnCode = gui->ClosePipe(PipeId); + PipeId = -1; + Running = 0; + { + char s[30]; + + sprintf(s, "[aborted, status=%d]", ReturnCode); + AddError(0, -1, 0, s); + } + return ErOK; + + case ExActivateInOtherWindow: + ShowError(View->Next, Row); + return ErOK; + } + return EList::ExecCommand(Command, State); +} + +void EMessages::AddError(Error *p) { + ErrCount++; + ErrList = (Error **) realloc(ErrList, sizeof(void *) * ErrCount); + ErrList[ErrCount - 1] = p; + ErrList[ErrCount - 1]->Buf = 0; + FindErrorFile(ErrCount - 1); + + if (ErrCount > Count) + if (Row >= Count - 1) { + //if (ErrCount > 1 && !ErrList[TopRow]->file) + Row = ErrCount - 1; + } + + UpdateList(); +} + +void EMessages::AddError(char *file, int line, char *msg, const char *text) { + Error *pe; + + pe = (Error *) malloc(sizeof(Error)); + if (pe == 0) + return ; + + pe->file = file ? strdup(file) : 0; + pe->line = line; + pe->msg = msg ? strdup(msg) : 0; + pe->text = text ? strdup(text) : 0; + + AddError(pe); +} + +void EMessages::FreeErrors() { + if (ErrList) { + for (int i = 0; i < ErrCount; i++) { + if (ErrList[i]->Buf != 0) { + char bk[16]; + sprintf(bk, "_MSG.%d", i); + ((EBuffer *)(ErrList[i]->Buf))->RemoveBookmark(bk); + } + free(ErrList[i]->msg); + free(ErrList[i]->text); + free(ErrList[i]->file); + free(ErrList[i]); + } + free(ErrList); + } + ErrCount = 0; + ErrList = 0; + BufLen = BufPos = 0; +} + +int EMessages::GetLine(char *Line, int maxim) { + int rc; + char *p; + int l; + + //fprintf(stderr, "GetLine: %d\n", Running); + + *Line = 0; + if (Running && PipeId != -1) { + rc = gui->ReadPipe(PipeId, MsgBuf + BufLen, sizeof(MsgBuf) - BufLen); + //fprintf(stderr, "GetLine: ReadPipe rc = %d\n", rc); + if (rc == -1) { + ReturnCode = gui->ClosePipe(PipeId); + PipeId = -1; + Running = 0; + } + if (rc > 0) + BufLen += rc; + } + l = maxim - 1; + if (BufLen - BufPos < l) + l = BufLen - BufPos; + //fprintf(stderr, "GetLine: Data %d\n", l); + p = (char *)memchr(MsgBuf + BufPos, '\n', l); + if (p) { + *p = 0; + strcpy(Line, MsgBuf + BufPos); + l = strlen(Line); + if (l > 0 && Line[l - 1] == '\r') + Line[l - 1] = 0; + BufPos = p + 1 - MsgBuf; + //fprintf(stderr, "GetLine: Line %d\n", strlen(Line)); + } else if (Running) { + memmove(MsgBuf, MsgBuf + BufPos, BufLen - BufPos); + BufLen -= BufPos; + BufPos = 0; + //fprintf(stderr, "GetLine: Line Incomplete\n"); + return 0; + } else { + if (l == 0) + return 0; + memcpy(Line, MsgBuf + BufPos, l); + Line[l] = 0; + if (l > 0 && Line[l - 1] == '\r') + Line[l - 1] = 0; + BufPos += l; + //fprintf(stderr, "GetLine: Line Last %d\n", l); + } + memmove(MsgBuf, MsgBuf + BufPos, BufLen - BufPos); + BufLen -= BufPos; + BufPos = 0; + //fprintf(stderr, "GetLine: Got Line\n"); + return 1; +} + + +static void getWord(char* dest, char*& pin) +{ + char *pout, *pend; + char ch, ec; + + while (*pin == ' ' || *pin == '\t') + pin++; + + pout = dest; + pend = dest + 256 - 1; + if (*pin == '\'' || *pin == '"' || *pin == '`') { + ec = *pin++; + if (ec == '`') + ec = '\''; + for (;;) { + ch = *pin++; + if (ch == '`') + ch = '\''; + if (ch == ec || ch == 0) + break; + + if (pout < pend) + *pout++ = ch; + } + if (ch == 0) + pin--; + } else { + for(;;) { + ch = *pin++; + if (ch == ' ' || ch == '\t' || ch == 0) + break; + if (pout < pend) *pout++ = ch; + } + } + *pout = 0; +} + + +void EMessages::GetErrors() { + char line[1024]; + RxMatchRes RM; + //int retc; + int i, n; + int didmatch = 0; + int WasRunning = Running; + char fn[256]; + + //fprintf(stderr, "Reading pipe\n"); + while (GetLine((char *)line, sizeof(line))) { + if (strlen(line) > 0 && line[strlen(line)-1] == '\n') line[strlen(line)-1] = 0; + didmatch = 0; + for (i = 0; i < NCRegexp; i++) { + if (RxExec(CRegexp[i].rx, line, strlen(line), line, &RM) == 1) { + char ln[256] = ""; + char msg[256] = ""; + char fn1[256] = ""; + char fn2[256] = ""; + char *file = 0; + *fn = 0; + + memset(fn, 0, 256); + memset(ln, 0, 256); + memset(msg, 0, 256); + n = CRegexp[i].RefFile; + if (RM.Close[n] - RM.Open[n] < 256) + memcpy(fn, line + RM.Open[n], RM.Close[n] - RM.Open[n]); + n = CRegexp[i].RefLine; + if (RM.Close[n] - RM.Open[n] < 256) + memcpy(ln, line + RM.Open[n], RM.Close[n] - RM.Open[n]); + n = CRegexp[i].RefMsg; + if (RM.Close[n] - RM.Open[n] < 256) + memcpy(msg, line + RM.Open[n], RM.Close[n] - RM.Open[n]); + + if (IsFullPath(fn)) + file = fn; + else { + if (curr_dir == 0) + strcpy(fn1, Directory); + else + strcpy(fn1, curr_dir->name); + Slash(fn1, 1); + strcat(fn1, fn); + if (ExpandPath(fn1, fn2) == 0) + file = fn2; + else + file = fn1; + } + AddError(file, atoi(ln), msg[0] ? msg : 0, line); + didmatch = 1; + MatchCount++; + break; + } + } + if (!didmatch) + { + AddError(0, -1, 0, line); + //** Quicky: check for gnumake 'entering directory' + //** make[x]: entering directory `xxx' + //** make[x]: leaving... + static char t1[] = "entering directory"; + static char t2[] = "leaving directory"; + char* pin; + + if ( (pin = strstr(line, "]:")) != 0) + { + //** It *is* some make line.. Check for 'entering'.. + pin += 2; + + //while(*pin != ':' && *pin != 0) pin++; + //pin++; + while (*pin == ' ') + pin++; + if (strnicmp(pin, t1, sizeof(t1)-1) == 0) { // Entering? + //** Get the directory name from the line, + pin += sizeof(t1)-1; + getWord(fn, pin); + //dbg("entering %s", fn); + + if (*fn) { + //** Indeedy entering directory! Link in list, + aDir * a = new aDir; + assert(a != 0); + a->name= strdup(fn); + assert(a->name != 0); + a->next = curr_dir; + curr_dir = a; + } + } else if (strnicmp(pin, t2, sizeof(t2)-1) == 0) { // Leaving? + pin += sizeof(t2)-1; + getWord(fn, pin); // Get dirname, + //dbg("leaving %s", fn); + + aDir *a; + + a = curr_dir; + if (a != 0) + curr_dir = curr_dir->next; // Remove from stack, + if (a != 0 && stricmp(a->name, fn) == 0) { + //** Pop this item. + free(a->name); + delete a; + } else { + //** Mismatch filenames -> error, and revoke stack. + //dbg("mismatch on %s", fn); + AddError(0, -1, 0, "fte: mismatch in directory stack!?"); + + //** In this case we totally die the stack.. + while(a != 0) + { + free(a->name); + delete a; + a = curr_dir; + if (a != 0) + curr_dir = curr_dir->next; + } + } + } + } + } + } + //fprintf(stderr, "Reading Stopped\n"); + if (!Running && WasRunning) { + char s[30]; + + sprintf(s, "[done, status=%d]", ReturnCode); + AddError(0, -1, 0, s); + } + //UpdateList(); + //NeedsUpdate = 1; +} + +int EMessages::CompilePrevError(EView *V) { + if (ErrCount > 0) { + bad: + if (Row > 0) { + Row--; + if (ErrList[Row]->line == -1 || !ErrList[Row]->file) goto bad; + ShowError(V, Row); + } else { + V->Msg(S_INFO, "No previous error."); + return 0; + } + } else { + V->Msg(S_INFO, "No errors."); + return 0; + } + return 1; +} + +int EMessages::CompileNextError(EView *V) { + if (ErrCount > 0) { + bad: + if (Row < ErrCount - 1) { + Row++; + if (ErrList[Row]->line == -1 || !ErrList[Row]->file) goto bad; + ShowError(V, Row); + } else { + if (Running) + V->Msg(S_INFO, "No more errors (yet)."); + else + V->Msg(S_INFO, "No more errors."); + return 0; + } + } else { + if (Running) + V->Msg(S_INFO, "No errors (yet)."); + else + V->Msg(S_INFO, "No errors."); + return 0; + } + return 1; +} + +int EMessages::Compile(char * /*Command*/) { + return 0; +} + +void EMessages::ShowError(EView *V, int err) { + if (err >= 0 && err < ErrCount) { + if (ErrList[err]->file) { + // should check if relative path + // possibly scan for (gnumake) directory info in output + if (ErrList[err]->Buf != 0) { + char bk[16]; + + V->SwitchToModel(ErrList[err]->Buf); + + sprintf(bk, "_MSG.%d", err); + ErrList[err]->Buf->GotoBookmark(bk); + } else { + if (FileLoad(0, ErrList[err]->file, 0, V) == 1) { + V->SwitchToModel(ActiveModel); + ((EBuffer *)ActiveModel)->CenterNearPosR(0, ErrList[err]->line - 1); + } + } + if (ErrList[err]->msg != 0) + V->Msg(S_INFO, "%s", ErrList[err]->msg); + else + V->Msg(S_INFO, "%s", ErrList[err]->text); + } + } +} + +void EMessages::DrawLine(PCell B, int Line, int Col, ChColor color, int Width) { + if (Line < ErrCount) + if (Col < int(strlen(ErrList[Line]->text))) { + char str[1024]; + int len; + + len = UnTabStr(str, sizeof(str), + ErrList[Line]->text, + strlen(ErrList[Line]->text)); + + if (len > Col) + MoveStr(B, 0, Width, str + Col, color, Width); + } +} + +char* EMessages::FormatLine(int Line) { + char *p; + if (Line < ErrCount) + p = strdup(ErrList[Line]->text); + else + p = 0; + return p; +} + +void EMessages::UpdateList() { + Count = ErrCount; + EList::UpdateList(); +} + +int EMessages::Activate(int No) { + //assert(No == Row); + //Row = No; + ShowError(View, Row); + return 1; +} + +int EMessages::CanActivate(int Line) { + int ok = 0; + if (Line < ErrCount) + if (ErrList[Line]->file || ErrList[Line]->line != -1) ok = 1; + return ok; +} + +void EMessages::NotifyPipe(int APipeId) { + //fprintf(stderr, "Got notified"); + if (APipeId == PipeId) + GetErrors(); +} + +void EMessages::GetName(char *AName, int MaxLen) { + strncpy(AName, "Messages", MaxLen); +} + +void EMessages::GetInfo(char *AInfo, int MaxLen) { + sprintf(AInfo, + "%2d %04d/%03d Messages: %d (%s) ", + ModelNo, + Row, Count, + MatchCount, + Command); +} + +void EMessages::GetPath(char *APath, int MaxLen) { + strncpy(APath, Directory, MaxLen); + APath[MaxLen - 1] = 0; + Slash(APath, 0); +} + +void EMessages::GetTitle(char *ATitle, int MaxLen, char *ASTitle, int SMaxLen) { + sprintf(ATitle, "Messages: %s", Command); + strncpy(ASTitle, "Messages", SMaxLen); + ASTitle[SMaxLen - 1] = 0; +} +#endif diff --git a/src/o_messages.h b/src/o_messages.h new file mode 100644 index 0000000..b9766f6 --- /dev/null +++ b/src/o_messages.h @@ -0,0 +1,90 @@ +/* o_messages.h + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#ifndef __MESSAGES_H__ +#define __MESSAGES_H__ + +#ifdef CONFIG_OBJ_MESSAGES +typedef struct { + char *file; + int line; + char *msg; + char *text; + EBuffer *Buf; +} Error; + +struct aDir +{ + aDir* next; + char* name; +}; + +class EMessages: public EList { +public: + char *Command; + char *Directory; + + int ErrCount; + Error **ErrList; + int Running; + + int BufLen; + int BufPos; + int PipeId; + int ReturnCode; + int MatchCount; + char MsgBuf[4096]; + aDir* curr_dir; // top of dir stack. + + EMessages(int createFlags, EModel **ARoot, char *Dir, char *ACommand); + ~EMessages(); + void freeDirStack(); + + virtual void NotifyDelete(EModel *Deleting); + void FindErrorFiles(); + void FindErrorFile(int err); + void AddFileError(EBuffer *B, int err); + void FindFileErrors(EBuffer *B); + + virtual int GetContext() { return CONTEXT_MESSAGES; } + virtual EEventMap *GetEventMap(); + virtual int ExecCommand(int Command, ExState &State); + + void AddError(Error *p); + void AddError(char *file, int line, char *msg, const char *text); + + void FreeErrors(); + int GetLine(char *Line, int maxim); + void GetErrors(); + int Compile(char *Command); + void ShowError(EView *V, int err); + void DrawLine(PCell B, int Line, int Col, ChColor color, int Width); + char* FormatLine(int Line); + void UpdateList(); + int Activate(int No); + int CanActivate(int Line); + void NotifyPipe(int APipeId); + virtual void GetName(char *AName, int MaxLen); + virtual void GetInfo(char *AInfo, int MaxLen); + virtual void GetPath(char *APath, int MaxLen); + virtual void GetTitle(char *ATitle, int MaxLen, char *ASTitle, int SMaxLen); + + int RunPipe(char *Dir, char *Command); + + int CompilePrevError(EView *V); + int CompileNextError(EView *V); +}; + +extern EMessages *CompilerMsgs; + +void FreeCRegexp(); + +#endif + +#endif diff --git a/src/o_model.cpp b/src/o_model.cpp new file mode 100644 index 0000000..7e7783b --- /dev/null +++ b/src/o_model.cpp @@ -0,0 +1,190 @@ +/* o_model.cpp + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#include "fte.h" + +EModel *ActiveModel = 0; +char msgbuftmp[MSGBUFTMP_SIZE] = ""; + +EModel *FindModelID(EModel *Model, int ID) { + EModel *M = Model; + int No = ID; + + while (M) { + if (M->ModelNo == No) + return M; + M = M->Next; + if (M == Model) + break; + } + return 0; +} + +int GetNewModelID(EModel *B) { + static int lastid = -1; + + while (FindModelID(B, ++lastid) != 0) /* */; + + return lastid; +} + +EModel::EModel(int createFlags, EModel **ARoot) { + Root = ARoot; + + if (Root) { + if (*Root) { + if (createFlags & cfAppend) { + Prev = *Root; + Next = (*Root)->Next; + } else { + Next = *Root; + Prev = (*Root)->Prev; + } + Prev->Next = this; + Next->Prev = this; + } else + Prev = Next = this; + + if (!(createFlags & cfNoActivate)) + *Root = this; + } else + Prev = Next = this; + View = 0; + ModelNo = -1; + ModelNo = GetNewModelID(this); +} + +EModel::~EModel() { + EModel *D = this; + + while (D) { + D->NotifyDelete(this); + D = D->Next; + if (D == this) + break; + } + + if (Next != this) { + Prev->Next = Next; + Next->Prev = Prev; + if (*Root == this) + *Root = Next; + } else + *Root = 0; +} + +void EModel::AddView(EView *V) { + RemoveView(V); + if (V) + V->NextView = View; + View = V; +} + +void EModel::RemoveView(EView *V) { + EView **X = &View; + + if (!V) return; + while (*X) { + if ((*X) == V) { + *X = V->NextView; + return; + } + X = (&(*X)->NextView); + } +} + +void EModel::SelectView(EView *V) { + RemoveView(V); + AddView(V); +} + +EViewPort *EModel::CreateViewPort(EView *V) { + return 0; +} + +int EModel::ExecCommand(int Command, ExState &State) { + return ErFAIL; +} + +void EModel::HandleEvent(TEvent &Event) { +} + +void EModel::Msg(int level, const char *s, ...) { + va_list ap; + + if (View == 0) + return; + + va_start(ap, s); + vsprintf(msgbuftmp, s, ap); + va_end(ap); + + if (level != S_BUSY) + View->SetMsg(msgbuftmp); +} + +int EModel::CanQuit() { + return 1; +} + +int EModel::ConfQuit(GxView *V, int multiFile) { + return 1; +} + +int EModel::GetContext() { return CONTEXT_NONE; } +EEventMap *EModel::GetEventMap() { return 0; } +int EModel::BeginMacro() { return 1; } +void EModel::GetName(char *AName, int MaxLen) { *AName = 0; } +void EModel::GetPath(char *APath, int MaxLen) { *APath = 0; } +void EModel::GetInfo(char *AInfo, int MaxLen) { *AInfo = 0; } +void EModel::GetTitle(char *ATitle, int MaxLen, char *ASTitle, int SMaxLen) { *ATitle = 0; *ASTitle = 0; } +void EModel::NotifyPipe(int PipeId) { } + +void EModel::NotifyDelete(EModel *Deleted) { +} +void EModel::DeleteRelated() { +} + +EViewPort::EViewPort(EView *V) { View = V; ReCenter = 0; } +EViewPort::~EViewPort() {} +void EViewPort::HandleEvent(TEvent &Event) { } +void EViewPort::UpdateView() { } +void EViewPort::RepaintView() { } +void EViewPort::UpdateStatus() { } +void EViewPort::RepaintStatus() { } +void EViewPort::GetPos() { } +void EViewPort::StorePos() { } +void EViewPort::Resize(int Width, int Height) {} + +void EModel::UpdateTitle() { + char Title[256] = ""; //fte: "; + char STitle[256] = ""; //"fte: "; + EView *V; + + GetTitle((char *)(Title + 0), sizeof(Title) - 0, + (char *)(STitle + 0), sizeof(STitle) - 0); + + V = View; + while (V) { + V->MView->Win->UpdateTitle(Title, STitle); + V = V->NextView; + } +} + +int EModel::GetStrVar(int var, char *str, int buflen) { + switch (var) { + case mvCurDirectory: + return GetDefaultDirectory(this, str, buflen); + } + return 0; +} + +int EModel::GetIntVar(int var, int *value) { + return 0; +} diff --git a/src/o_model.h b/src/o_model.h new file mode 100644 index 0000000..815d704 --- /dev/null +++ b/src/o_model.h @@ -0,0 +1,176 @@ +/* o_model.h + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#ifndef __MODEL_H__ +#define __MODEL_H__ + +class EView; + +class EViewPort { +public: + EView *View; + int ReCenter; + + EViewPort(EView *V); + virtual ~EViewPort(); + + virtual void HandleEvent(TEvent &Event); + virtual void UpdateView(); + virtual void RepaintView(); + virtual void UpdateStatus(); + virtual void RepaintStatus(); + + virtual void GetPos(); + virtual void StorePos(); + + virtual void Resize(int Width, int Height); +}; + +enum createFlags { + cfAppend = 1, + cfNoActivate = 2 +}; + +class EModel { +public: + EModel **Root; // root ptr of this list + EModel *Next; // next model + EModel *Prev; // prev model + EView *View; // active view of model + + int ModelNo; + + EModel(int createFlags, EModel **ARoot); + virtual ~EModel(); + + void AddView(EView *V); + void RemoveView(EView *V); + void SelectView(EView *V); + + virtual EViewPort *CreateViewPort(EView *V); + + virtual int GetContext(); + virtual EEventMap *GetEventMap(); + virtual int BeginMacro(); + virtual int ExecCommand(int Command, ExState &State); + virtual void HandleEvent(TEvent &Event); + + virtual void GetName(char *AName, int MaxLen); + virtual void GetPath(char *APath, int MaxLen); + virtual void GetInfo(char *AInfo, int MaxLen); + virtual void GetTitle(char *ATitle, int MaxLen, + char *ASTitle, int SMaxLen); + + void UpdateTitle(); + + void Msg(int level, const char *s, ...); + virtual int CanQuit(); + virtual int ConfQuit(GxView *V, int multiFile = 0); + + virtual int GetStrVar(int var, char *str, int buflen); + virtual int GetIntVar(int var, int *value); + + virtual void NotifyPipe(int PipeId); + + virtual void NotifyDelete(EModel *Deleting); + virtual void DeleteRelated(); +}; + +class EView { +public: + EView *Next; // next view + EView *Prev; // prev view + ExModelView *MView; // model view controller + EModel *Model; // model for this view + EView *NextView; // next view for model + EViewPort *Port; + char *CurMsg; + + EView(EModel *AModel); + virtual ~EView(); + + virtual void FocusChange(int GotFocus); + virtual void Resize(int Width, int Height); + + void SetModel(EModel *AModel); + void SelectModel(EModel *AModel); + void SwitchToModel(EModel *AModel); + + void Activate(int GotFocus); + + virtual int GetContext(); + virtual EEventMap *GetEventMap(); + virtual int BeginMacro(); + virtual int ExecCommand(int Command, ExState &State); + + virtual void HandleEvent(TEvent &Event); + virtual void UpdateView(); + virtual void RepaintView(); + virtual void UpdateStatus(); + virtual void RepaintStatus(); + + void Msg(int level, const char *s, ...); + void SetMsg(char *Msg); + + int SwitchTo(ExState &State); + int FilePrev(); + int FileNext(); + int FileLast(); + int FileSaveAll(); + int FileOpen(ExState &State); + int FileOpenInMode(ExState &State); + int SetPrintDevice(ExState &State); + int ToggleSysClipboard(ExState &State); + int ShowKey(ExState &State); + int ViewBuffers(ExState &State); +#ifdef CONFIG_OBJ_ROUTINE + int ViewRoutines(ExState &State); +#endif +#ifdef CONFIG_OBJ_MESSAGES + int Compile(ExState &State); + int RunCompiler(ExState &State); + int Compile(char *Command); + int ViewMessages(ExState &State); + int CompilePrevError(ExState &State); + int CompileNextError(ExState &State); + int ConfigRecompile(ExState &State); +#endif +#ifdef CONFIG_OBJ_DIRECTORY + int DirOpen(ExState &State); + int OpenDir(char *Directory); +#endif + int ShowVersion(); + int ViewModeMap(ExState &State); + int ClearMessages(); +#ifdef CONFIG_TAGS + int TagLoad(ExState &State); +#endif + int SysShowHelp(ExState &State, const char *word); + + int RemoveGlobalBookmark(ExState &State); + int GotoGlobalBookmark(ExState &State); + int PopGlobalBookmark(); + + void DeleteModel(EModel *M); + int CanQuit(); + + int GetStrVar(int var, char *str, int buflen); + int GetIntVar(int var, int *value); +}; + +extern EModel *ActiveModel; +extern EView *ActiveView; + +int GetNewModelID(EModel *B); +EModel *FindModelID(EModel *B, int ID); + +#define MSGBUFTMP_SIZE 1024 +extern char msgbuftmp[MSGBUFTMP_SIZE]; + +#endif diff --git a/src/o_modemap.cpp b/src/o_modemap.cpp new file mode 100644 index 0000000..4f80f58 --- /dev/null +++ b/src/o_modemap.cpp @@ -0,0 +1,174 @@ +/* o_modemap.cpp + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#include "fte.h" + +EventMapView *TheEventMapView = 0; + +void EventMapView::AddLine(const char *Line) { + if (BList) { + BCount++; + BList = (char **)realloc((void *)BList, sizeof(char *) * BCount); + } else { + BCount = 1; + BList = (char **)malloc(sizeof(char *)); + } + assert(BList); + BList[BCount - 1] = strdup(Line); +} + +void EventMapView::DumpKey(const char *aPrefix, EKey *Key) { + char KeyName[128] = ""; + char Entry[2048] = ""; + char *p; + int id; + + if (aPrefix) { + strcpy(KeyName, aPrefix); + strcat(KeyName, "_"); + } + GetKeyName(KeyName + strlen(KeyName), Key->fKey); + sprintf(Entry, "%13s ", KeyName); + id = Key->Cmd; + for (int i = 0; i < Macros[id].Count; i++) { + p = Entry + strlen(Entry); + if (Macros[id].cmds[i].type == CT_COMMAND) { + if (Macros[id].cmds[i].repeat > 1) + sprintf(p, "%d:%s ", Macros[id].cmds[i].repeat, GetCommandName(Macros[id].cmds[i].u.num)); + else + sprintf(p, "%s ", GetCommandName(Macros[id].cmds[i].u.num)); + } else if (Macros[id].cmds[i].type == CT_NUMBER) { + sprintf(p, "%ld ", Macros[id].cmds[i].u.num); + } else if (Macros[id].cmds[i].type == CT_STRING) { + sprintf(p, "'%s' ", Macros[id].cmds[i].u.string); + } + if (strlen(Entry) > 1950) { + strcat(Entry, "..."); + break; + } + } + AddLine(Entry); +} + +void EventMapView::DumpMap(const char *aPrefix, EKeyMap *aKeyMap) { + EKey *Key; + + Key = aKeyMap->fKeys; + while (Key) { + if (Key->fKeyMap) { + char Prefix[32] = ""; + + if (aPrefix) { + strcpy(Prefix, aPrefix); + strcat(Prefix, "_"); + } + GetKeyName(Prefix + strlen(Prefix), Key->fKey); + DumpMap(Prefix, Key->fKeyMap); + } else { + DumpKey(aPrefix, Key); + } + Key = Key->fNext; + } +} + +void EventMapView::DumpEventMap(EEventMap *aEventMap) { + char name[256]; + + while (aEventMap) { + strcpy(name, aEventMap->Name); + if (aEventMap->Parent) { + strcat(name, ": "); + strcat(name, aEventMap->Parent->Name); + } + AddLine(name); + if (aEventMap->KeyMap) + DumpMap(0, aEventMap->KeyMap); + aEventMap = aEventMap->Parent; + if (aEventMap != 0) + AddLine(""); + } +} + +EventMapView::EventMapView(int createFlags, EModel **ARoot, EEventMap *Map): EList(createFlags, ARoot, "Event Map") { + BCount = 0; + BList = 0; + DumpEventMap(EMap = Map); + TheEventMapView = this; +} + +EventMapView::~EventMapView() { + FreeView(); + TheEventMapView = 0; +} + +void EventMapView::FreeView() { + if (BList) { + for (int i = 0; i < BCount; i++) + if (BList[i]) + free(BList[i]); + free(BList); + } + BCount = 0; + BList = 0; +} + +void EventMapView::ViewMap(EEventMap *Map) { + FreeView(); + DumpEventMap(EMap = Map); +} + +EEventMap *EventMapView::GetEventMap() { + return FindEventMap("EVENTMAPVIEW"); +} + +int EventMapView::ExecCommand(int Command, ExState &State) { + return EList::ExecCommand(Command, State); +} + +int EventMapView::GetContext() { + return CONTEXT_MAPVIEW; +} + +void EventMapView::DrawLine(PCell B, int Line, int Col, ChColor color, int Width) { + if (Line < BCount) + if (Col < int(strlen(BList[Line]))) + MoveStr(B, 0, Width, BList[Line] + Col, color, Width); +} + +char *EventMapView::FormatLine(int Line) { + return strdup(BList[Line]); +} + +void EventMapView::UpdateList() { + Count = BCount; + EList::UpdateList(); +} + +int EventMapView::CanActivate(int /*Line*/) { + return 0; +} + +void EventMapView::GetName(char *AName, int MaxLen) { + strncpy(AName, "EventMapView", MaxLen); +} + +void EventMapView::GetInfo(char *AInfo, int MaxLen) { + sprintf(AInfo, + "%2d %04d/%03d EventMapView (%s)", + ModelNo, + Row + 1, Count, + EMap->Name); +} + +void EventMapView::GetTitle(char *ATitle, int MaxLen, char *ASTitle, int SMaxLen) { + sprintf(ATitle, "EventMapView: %s", EMap->Name); + strncpy(ASTitle, "EventMapView", SMaxLen); + ASTitle[SMaxLen - 1] = 0; +} + diff --git a/src/o_modemap.h b/src/o_modemap.h new file mode 100644 index 0000000..93af3f6 --- /dev/null +++ b/src/o_modemap.h @@ -0,0 +1,45 @@ +/* o_modemap.h + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#ifndef __MAPVIEW_H__ +#define __MAPVIEW_H__ + +class EventMapView: public EList { +public: + char **BList; + int BCount; + EEventMap *EMap; + + void AddLine(const char *Line); + void DumpKey(const char *aPrefix, EKey *Key); + void DumpMap(const char *aPrefix, EKeyMap *aKeyMap); + void DumpEventMap(EEventMap *aEventMap); + + EventMapView(int createFlags, EModel **ARoot, EEventMap *Map); + virtual ~EventMapView(); + + void FreeView(); + void ViewMap(EEventMap *Map); + + virtual int ExecCommand(int Command, ExState &State); + virtual EEventMap *GetEventMap(); + virtual int GetContext(); + + virtual void DrawLine(PCell B, int Line, int Col, ChColor color, int Width); + virtual char* FormatLine(int Line); + virtual void UpdateList(); + virtual int CanActivate(int Line); + virtual void GetName(char *AName, int MaxLen); + virtual void GetInfo(char *AInfo, int MaxLen); + virtual void GetTitle(char *ATitle, int MaxLen, char *ASTitle, int SMaxLen); +}; + +extern EventMapView *TheEventMapView; + +#endif diff --git a/src/o_routine.cpp b/src/o_routine.cpp new file mode 100644 index 0000000..ce4b8e9 --- /dev/null +++ b/src/o_routine.cpp @@ -0,0 +1,121 @@ +/* o_routine.cpp + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#include "fte.h" + +#ifdef CONFIG_OBJ_ROUTINE +RoutineView::RoutineView(int createFlags, EModel **ARoot, EBuffer *AB): EList(createFlags, ARoot, "Routines") { + Buffer = AB; + if (Buffer->rlst.Count == 0) + Buffer->ScanForRoutines(); + Row = 0; + int Row = Buffer->VToR(Buffer->CP.Row); + for (int i = Buffer->rlst.Count - 1; i >= 0; --i) + if (Row >= Buffer->rlst.Lines[i]) { + Row = i; + break; + } + { + char CTitle[256]; + + sprintf(CTitle, "Routines %s: %d", + Buffer->FileName, + Buffer->rlst.Count); + SetTitle(CTitle); + } +}; + +RoutineView::~RoutineView() { + Buffer->Routines = 0; +} + +EEventMap *RoutineView::GetEventMap() { + return FindEventMap("ROUTINES"); +} + +int RoutineView::ExecCommand(int Command, ExState &State) { + switch (Command) { + case ExRescan: + Buffer->ScanForRoutines(); + UpdateList(); + return ErOK; + + case ExActivateInOtherWindow: + if (Row < Buffer->rlst.Count) { + View->Next->SwitchToModel(Buffer); + Buffer->CenterPosR(0, Buffer->rlst.Lines[Row]); + return ErOK; + } + return ErFAIL; + + case ExCloseActivate: + return ErFAIL; + } + return EList::ExecCommand(Command, State); +} + +void RoutineView::DrawLine(PCell B, int Line, int Col, ChColor color, int Width) { + if (Buffer->RLine(Buffer->rlst.Lines[Line])->Count > Col) { + char str[1024]; + int len; + + len = UnTabStr(str, sizeof(str), + Buffer->RLine(Buffer->rlst.Lines[Line])->Chars, + Buffer->RLine(Buffer->rlst.Lines[Line])->Count); + + if (len > Col) + MoveStr(B, 0, Width, str + Col, color, len - Col); + } +} + +char* RoutineView::FormatLine(int Line) { + char *p = 0; + PELine L = Buffer->RLine(Buffer->rlst.Lines[Line]); + + p = (char *) malloc(L->Count + 1); + if (p) { + memcpy(p, L->Chars, L->Count); + p[L->Count] = 0; + } + return p; +} + +int RoutineView::Activate(int No) { + if (No < Buffer->rlst.Count) { + View->SwitchToModel(Buffer); + Buffer->CenterPosR(0, Buffer->rlst.Lines[No]); + return 1; + } + return 0; +} + +void RoutineView::RescanList() { + Buffer->ScanForRoutines(); + UpdateList(); + NeedsRedraw = 1; +} + +void RoutineView::UpdateList() { + Count = Buffer->rlst.Count; +} + +void RoutineView::GetName(char *AName, int MaxLen) { + strncpy(AName, "Routines", MaxLen); +} + +void RoutineView::GetInfo(char *AInfo, int MaxLen) { + sprintf(AInfo, "%2d %04d/%03d Routines (%s)", ModelNo, Row + 1, Count, Buffer->FileName); +} + +void RoutineView::GetTitle(char *ATitle, int MaxLen, char *ASTitle, int SMaxLen) { + sprintf(ATitle, "Routines: %s", Buffer->FileName); + strncpy(ASTitle, "Routines", SMaxLen); + ASTitle[SMaxLen - 1] = 0; +} +#endif diff --git a/src/o_routine.h b/src/o_routine.h new file mode 100644 index 0000000..567f68c --- /dev/null +++ b/src/o_routine.h @@ -0,0 +1,34 @@ +/* o_routine.h + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#ifndef __ROUTINE_H__ +#define __ROUTINE_H__ + +#ifdef CONFIG_OBJ_ROUTINE + +class RoutineView: public EList { +public: + EBuffer *Buffer; + + RoutineView(int createFlags, EModel **ARoot, EBuffer *AB); + virtual ~RoutineView(); + virtual EEventMap *GetEventMap(); + virtual int ExecCommand(int Command, ExState &State); + virtual void DrawLine(PCell B, int Line, int Col, ChColor color, int Width); + virtual char* FormatLine(int Line); + virtual int Activate(int No); + virtual void RescanList(); + void UpdateList(); + virtual void GetName(char *AName, int MaxLen); + virtual void GetInfo(char *AInfo, int MaxLen); + virtual void GetTitle(char *ATitle, int MaxLen, char *ASTitle, int SMaxLen); +}; +#endif + +#endif diff --git a/src/objs.inc b/src/objs.inc new file mode 100644 index 0000000..c3eed86 --- /dev/null +++ b/src/objs.inc @@ -0,0 +1,143 @@ +CFTE_OBJS = \ +cfte.$(OEXT) \ +s_files.$(OEXT) + +OBJS = \ +indent.$(OEXT) \ +e_mark.$(OEXT) \ +o_modemap.$(OEXT) \ +c_desktop.$(OEXT) \ +c_bind.$(OEXT) \ +c_color.$(OEXT) \ +c_config.$(OEXT) \ +c_history.$(OEXT) \ +c_hilit.$(OEXT) \ +c_mode.$(OEXT) \ +e_block.$(OEXT) \ +e_buffer.$(OEXT) \ +e_cmds.$(OEXT) \ +e_redraw.$(OEXT) \ +e_file.$(OEXT) \ +e_fold.$(OEXT) \ +e_trans.$(OEXT) \ +e_line.$(OEXT) \ +e_loadsave.$(OEXT) \ +e_regex.$(OEXT) \ +e_print.$(OEXT) \ +e_search.$(OEXT) \ +e_undo.$(OEXT) \ +e_tags.$(OEXT) \ +g_draw.$(OEXT) \ +g_menu.$(OEXT) \ +h_ada.$(OEXT) \ +h_c.$(OEXT) \ +h_fte.$(OEXT) \ +h_html.$(OEXT) \ +h_ipf.$(OEXT) \ +h_make.$(OEXT) \ +h_merge.$(OEXT) \ +h_pascal.$(OEXT) \ +h_perl.$(OEXT) \ +h_plain.$(OEXT) \ +h_msg.$(OEXT) \ +h_rexx.$(OEXT) \ +h_sh.$(OEXT) \ +h_tex.$(OEXT) \ +h_diff.$(OEXT) \ +h_catbs.$(OEXT) \ +h_simple.$(OEXT) \ +i_complete.$(OEXT) \ +i_ascii.$(OEXT) \ +i_choice.$(OEXT) \ +i_input.$(OEXT) \ +i_key.$(OEXT) \ +i_search.$(OEXT) \ +i_view.$(OEXT) \ +i_modelview.$(OEXT) \ +i_oview.$(OEXT) \ +o_buflist.$(OEXT) \ +o_list.$(OEXT) \ +o_messages.$(OEXT) \ +o_model.$(OEXT) \ +o_routine.$(OEXT) \ +o_buffer.$(OEXT) \ +o_directory.$(OEXT) \ +s_files.$(OEXT) \ +s_direct.$(OEXT) \ +s_util.$(OEXT) \ +view.$(OEXT) \ +gui.$(OEXT) \ +egui.$(OEXT) \ +fte.$(OEXT) \ +commands.$(OEXT) \ +log.$(OEXT) + +OS2OBJS = e_os2.$(OEXT) + +VIOOBJS = $(OS2OBJS) \ +g_text.$(OEXT) \ +menu_text.$(OEXT) \ +con_os2.$(OEXT) \ +clip_os2.$(OEXT) \ +clip_pmv.$(OEXT) \ +g_nodlg.$(OEXT) + +PMOBJS = $(OS2OBJS) \ +g_pm.$(OEXT) \ +clip_os2.$(OEXT) \ +clip_pm.$(OEXT) + +UNIXOBJS = \ +e_unix.$(OEXT) \ +memicmp.$(OEXT) + +XOBJS = $(UNIXOBJS) \ +g_text.$(OEXT) \ +menu_text.$(OEXT) \ +con_x11.$(OEXT) \ +clip_x11.$(OEXT) \ +con_i18n.$(OEXT) \ +g_nodlg.$(OEXT) + +QOBJS = $(UNIXOBJS) \ +g_qt.$(OEXT) \ +g_qt_dlg.$(OEXT) \ +clip_x11.$(OEXT) + +SOBJS = $(UNIXOBJS) \ +g_text.$(OEXT) \ +menu_text.$(OEXT) \ +con_slang.$(OEXT) \ +clip_no.$(OEXT) \ +g_nodlg.$(OEXT) + +VOBJS = $(UNIXOBJS) \ +g_text.$(OEXT) \ +menu_text.$(OEXT) \ +con_linux.$(OEXT) \ +clip_no.$(OEXT) \ +g_nodlg.$(OEXT) + +MOBJS = $(UNIXOBJS) \ +g_motif.$(OEXT) \ +clip_no.$(OEXT) \ +g_nodlg.$(OEXT) + +NTOBJS = \ +g_text.$(OEXT) \ +menu_text.$(OEXT) \ +con_nt.$(OEXT) \ +clip_os2.$(OEXT) \ +g_nodlg.$(OEXT) \ +e_win32.$(OEXT) + +DOSP32OBJS = \ +memicmp.$(OEXT) \ +port.$(OEXT) \ +portdos.$(OEXT) \ +g_text.$(OEXT) \ +menu_text.$(OEXT) \ +con_dosx.$(OEXT) \ +clip_no.$(OEXT) \ +g_nodlg.$(OEXT) \ +e_djgpp2.$(OEXT) diff --git a/src/pm_tool.cpp b/src/pm_tool.cpp new file mode 100644 index 0000000..e33b6c9 --- /dev/null +++ b/src/pm_tool.cpp @@ -0,0 +1,403 @@ + +#define InRange(a,x,b) (((a) <= (x)) && ((x) < (b))) +#define Min(a,b) (((a) < (b))?(a):(b)) +#define Max(a,b) (((a) > (b))?(a):(b)) + +#define TYBORDER 6 // border on top and bottom of icon (all of it) +#define TXBORDER 6 +#define TXSEPARATOR 4 +#define TYICON 24 +#define TXICON 24 + +MRESULT EXPENTRY ToolBarProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2) { + if (msg == WM_CREATE) { + WinSetWindowPtr(hwnd, QWL_USER, PVOIDFROMMP(mp1)); + } else { + ToolBarData *td = (ToolBarData *)WinQueryWindowPtr(hwnd, QWL_USER); + ToolBarItem *items = td->pItems; + + switch (msg) { + case WM_DESTROY: + free(td); + free(items); + break; + + case WM_PAINT: + { + HPS hps; + RECTL rcl; + POINTL ptl; + SWP swp; + int xpos, ypos, item; + + WinQueryWindowPos(hwnd, &swp); + + hps = WinBeginPaint(hwnd, 0, &rcl); + + /* top outside 3D border */ + if (rcl.yBottom < 1) { + GpiSetColor(hps, CLR_DARKGRAY); + ptl.x = rcl.xLeft; + ptl.y = 0; + GpiMove(hps, &ptl); + ptl.x = Min(rcl.xRight, swp.cx - 2); + GpiLine(hps, &ptl); + } + + /* bottom outside 3D border */ + if (rcl.yTop >= swp.cy - 1 - 1) { + GpiSetColor(hps, CLR_WHITE); + ptl.x = Max(rcl.xLeft, 1); + ptl.y = swp.cy - 1; + GpiMove(hps, &ptl); + ptl.x = rcl.xRight; + GpiLine(hps, &ptl); + } + + /* 3D corners */ + GpiSetColor(hps, CLR_PALEGRAY); + ptl.x = 0; + ptl.y = 0; + GpiSetPel(hps, &ptl); + ptl.x = swp.cx - 1; + ptl.y = swp.cy - 1; + GpiSetPel(hps, &ptl); + + /* bottom space */ + if (rcl.yBottom < TYBORDER - 1) { + for (ptl.y = 1; ptl.y < TYBORDER - 2; ptl.y++) { + ptl.x = Max(rcl.xLeft, 1); + GpiMove(hps, &ptl); + ptl.x = Min(rcl.xRight, swp.cx - 1); + GpiLine(hps, &ptl); + } + } + + /* top space */ + if (rcl.yTop >= swp.cy - TYBORDER + 2) { + for (ptl.y = swp.cy - TYBORDER + 2; ptl.y < swp.cy - 1; ptl.y++) { + ptl.x = Max(rcl.xLeft, 1); + GpiMove(hps, &ptl); + ptl.x = Min(rcl.xRight, swp.cx - 1); + GpiLine(hps, &ptl); + } + } + + /* left outside 3D border */ + if (rcl.xLeft < 1) { + GpiSetColor(hps, CLR_WHITE); + ptl.y = Max(1, rcl.yBottom); + ptl.x = 0; + GpiMove(hps, &ptl); + ptl.y = rcl.yTop; + GpiLine(hps, &ptl); + } + + /* right outside 3D border */ + if (rcl.xRight >= swp.cx - 1) { + GpiSetColor(hps, CLR_DARKGRAY); + ptl.y = rcl.yBottom; + ptl.x = swp.cx - 1; + GpiMove(hps, &ptl); + ptl.y = Min(swp.cy - 2, rcl.yTop); + GpiLine(hps, &ptl); + } + + /* left border */ + if (rcl.xLeft < TXBORDER - 2) { + GpiSetColor(hps, CLR_PALEGRAY); + for (ptl.x = 1; ptl.x < TXBORDER - 2; ptl.x++) { + ptl.y = Max(1, rcl.yBottom); + GpiMove(hps, &ptl); + ptl.y = Min(swp.cy - 2, rcl.yTop); + GpiLine(hps, &ptl); + } + } + + /* draw toolbar items */ + xpos = TXBORDER; + ypos = TYBORDER; + + for (item = 0; item < td->ulCount; item++) { + if (items[item].ulType == tiBITMAP) { + if (rcl.xRight >= xpos - 2 && rcl.xLeft <= xpos + TXICON + 1) { + GpiSetColor(hps, CLR_BLACK); + ptl.x = xpos - 2; + ptl.y = ypos - 2; + GpiMove(hps, &ptl); + ptl.x = xpos + TXICON + 1; + ptl.y = ypos + TYICON + 1; + GpiBox(hps, DRO_OUTLINE, &ptl, 0, 0); + if (item == td->ulDepressed && (items[item].ulFlags & tfDEPRESSED)) { + ptl.x = xpos + 1; + ptl.y = ypos - 1; + WinDrawBitmap(hps, + items[item].hBitmap, + 0, + &ptl, + 0, 0, + (items[item].ulFlags & tfDISABLED) ? DBM_INVERT: DBM_NORMAL); + + GpiSetColor(hps, CLR_DARKGRAY); + ptl.x = xpos - 1; + ptl.y = ypos - 1; + GpiMove(hps, &ptl); + ptl.y = ypos + TYICON; + GpiLine(hps, &ptl); + ptl.x = xpos + TXICON; + GpiLine(hps, &ptl); + ptl.y--; + GpiMove(hps, &ptl); + ptl.x = xpos; + GpiLine(hps, &ptl); + ptl.y = ypos - 1; + GpiLine(hps, &ptl); + } else { + ptl.x = xpos; + ptl.y = ypos; + WinDrawBitmap(hps, + items[item].hBitmap, + 0, + &ptl, + 0, 0, + (items[item].ulFlags & tfDISABLED) ? DBM_INVERT: DBM_NORMAL); + + GpiSetColor(hps, CLR_PALEGRAY); + ptl.x = xpos - 1; + ptl.y = ypos - 1; + GpiSetPel(hps, &ptl); + GpiSetColor(hps, CLR_WHITE); + ptl.y++; + GpiMove(hps, &ptl); + ptl.y = ypos + TYICON; + GpiLine(hps, &ptl); + ptl.x = xpos + TXICON - 1; + GpiLine(hps, &ptl); + GpiSetColor(hps, CLR_PALEGRAY); + ptl.x++; + GpiSetPel(hps, &ptl); + ptl.y--; + GpiSetColor(hps, CLR_DARKGRAY); + GpiMove(hps, &ptl); + ptl.y = ypos - 1; + GpiLine(hps, &ptl); + ptl.x = xpos; + GpiLine(hps, &ptl); + } + } + xpos += TXICON + 3; + } else if (items[item].ulType == tiSEPARATOR) { + if (rcl.xRight >= xpos - 1 && rcl.xLeft <= xpos + TXSEPARATOR + 1) { + GpiSetColor(hps, CLR_PALEGRAY); + ptl.x = xpos - 1; + ptl.y = ypos - 2; + GpiMove(hps, &ptl); + ptl.x = xpos + TXSEPARATOR + 1; + ptl.y = ypos + TYICON + 1; + GpiBox(hps, DRO_FILL, &ptl, 0, 0); + } + xpos += TXSEPARATOR + 3; + } + } + GpiSetColor(hps, CLR_PALEGRAY); + ptl.x = xpos - 1; + ptl.y = ypos - 2; + GpiMove(hps, &ptl); + ptl.x = swp.cx - 2; + ptl.y = swp.cy - TYBORDER + 1; + GpiBox(hps, DRO_FILL, &ptl, 0, 0); + + WinEndPaint(hps); + } + break; + + case WM_ADJUSTWINDOWPOS: + { + PSWP pswp = (PSWP)PVOIDFROMMP(mp1); + pswp->cy = TYBORDER + TYICON + TYBORDER; + } + break; + + case WM_BUTTON1DOWN: + case WM_BUTTON1DBLCLK: + { + int item; + POINTL ptl; + RECTL rcl; + + ptl.x = (LONG) SHORT1FROMMP(mp1); + ptl.y = (LONG) SHORT2FROMMP(mp1); + + rcl.yBottom = TYBORDER - 1; + rcl.yTop = TYBORDER + TYICON + 1; + rcl.xLeft = TXBORDER - 1; + rcl.xRight = TXBORDER + TXICON + 1; + + for (item = 0; item < td->ulCount; item++) { + if (rcl.xLeft <= ptl.x && rcl.yBottom <= ptl.y && + rcl.xRight >= ptl.x && rcl.yTop >= ptl.y && + td->pItems[item].ulType == tiBITMAP && + (td->pItems[item].ulFlags & tfDISABLED) == 0) + { + td->ulDepressed = item; + td->pItems[item].ulFlags |= tfDEPRESSED; + WinInvalidateRect(hwnd, &rcl, FALSE); + WinSetCapture(HWND_DESKTOP, hwnd); + break; + } + if (td->pItems[item].ulType == tiBITMAP) { + rcl.xLeft += TXICON + 3; + rcl.xRight += TXICON + 3; + } else if (td->pItems[item].ulType == tiSEPARATOR) { + rcl.xLeft += TXSEPARATOR + 3; + rcl.xRight += TXSEPARATOR + 3; + } + } + } + break; + + case WM_MOUSEMOVE: + { + STARTFUNC("ToolBarProc[WM_MOUSEMOVE]"); + int item; + POINTL ptl; + RECTL rcl; + + if (td->ulDepressed == -1) + break; + + ptl.x = (LONG) SHORT1FROMMP(mp1); + ptl.y = (LONG) SHORT2FROMMP(mp1); + + rcl.yBottom = TYBORDER - 1; + rcl.yTop = TYBORDER + TYICON + 1; + rcl.xLeft = TXBORDER - 1; + rcl.xRight = TXBORDER + TXICON + 1; + + LOG << "Depressed: " << td-> ulDepressed << ENDLINE; + for (item = 0; item < td->ulCount; item++) { + LOG << "Checking item " << item << ENDLINE; + LOG << " pItem -> " << (void*)(td->pItems + item) << ENDLINE; + if (item == td->ulDepressed) { + if (rcl.xLeft <= ptl.x && rcl.yBottom <= ptl.y && + rcl.xRight >= ptl.x && rcl.yTop >= ptl.y) + { + if ((td->pItems[item].ulFlags & tfDEPRESSED) == 0) { + td->pItems[item].ulFlags |= tfDEPRESSED; + WinInvalidateRect(hwnd, &rcl, FALSE); + } + } else { + if (td->pItems[item].ulFlags & tfDEPRESSED) { + td->pItems[item].ulFlags &= ~tfDEPRESSED; + WinInvalidateRect(hwnd, &rcl, FALSE); + } + } + break; + } + if (td->pItems[item].ulType == tiBITMAP) { + rcl.xLeft += TXICON + 3; + rcl.xRight += TXICON + 3; + } else if (td->pItems[item].ulType == tiSEPARATOR) { + rcl.xLeft += TXSEPARATOR + 3; + rcl.xRight += TXSEPARATOR + 3; + } + } + } + break; + + case WM_BUTTON1UP: + { + int item; + POINTL ptl; + RECTL rcl; + + if (td->ulDepressed == -1) + break; + + ptl.x = (LONG) SHORT1FROMMP(mp1); + ptl.y = (LONG) SHORT2FROMMP(mp1); + + rcl.yBottom = TYBORDER - 1; + rcl.yTop = TYBORDER + TYICON + 1; + rcl.xLeft = TXBORDER - 1; + rcl.xRight = TXBORDER + TXICON + 1; + + for (item = 0; item < td->ulCount; item++) { + if (item == td->ulDepressed) { + WinSetCapture(HWND_DESKTOP, (HWND)0); + if (rcl.xLeft <= ptl.x && rcl.yBottom <= ptl.y && + rcl.xRight >= ptl.x && rcl.yTop >= ptl.y && + td->pItems[item].ulFlags & tfDEPRESSED) + { + td->pItems[item].ulFlags &= ~tfDEPRESSED; + WinInvalidateRect(hwnd, &rcl, FALSE); + + // message + WinPostMsg(WinQueryWindow(hwnd, QW_OWNER), WM_COMMAND, MPFROM2SHORT(td->pItems[item].ulCommand, 0), MPFROM2SHORT(CMDSRC_OTHER, TRUE)); + + break; + } + } + if (td->pItems[item].ulType == tiBITMAP) { + rcl.xLeft += TXICON + 3; + rcl.xRight += TXICON + 3; + } else if (td->pItems[item].ulType == tiSEPARATOR) { + rcl.xLeft += TXSEPARATOR + 3; + rcl.xRight += TXSEPARATOR + 3; + } + } + td->ulDepressed = -1; + } + break; + } + } + return WinDefWindowProc(hwnd, msg, mp1, mp2); +} + +void RegisterToolBarClass(HAB hab) { + assert(WinRegisterClass(hab, + WC_MTOOLBAR, + (PFNWP)ToolBarProc, + CS_SIZEREDRAW, + sizeof(void *)) == TRUE); +} + +HWND CreateToolBar(HWND parent, + HWND owner, + ULONG id, + ULONG count, + ToolBarItem *items) +{ + STARTFUNC("CreateToolBar"); + ToolBarData *td; + HWND hwnd; + + td = (ToolBarData *)malloc(sizeof(ToolBarData)); + if (td == 0) + return 0; + td->pItems = (ToolBarItem *)malloc(sizeof(ToolBarItem) * count); + if (td->pItems == 0) + { + free(td); + return 0; + } + + td->cb = sizeof(ToolBarData); + td->ulCount = count; + td->ulDepressed = (LONG)-1; + memcpy((void *)td->pItems, (void *)items, sizeof(ToolBarItem) * count); + + hwnd = WinCreateWindow(parent, + WC_MTOOLBAR, + "ToolBar", + WS_VISIBLE, + 0, 0, 0, 0, + owner, + HWND_TOP, + id, + td, + 0); + + //free(td); <-- Don't do this here as now the window owns the memory! + return hwnd; +} diff --git a/src/pm_tool.h b/src/pm_tool.h new file mode 100644 index 0000000..628ef49 --- /dev/null +++ b/src/pm_tool.h @@ -0,0 +1,35 @@ +#ifndef __TOOLBAR_H +#define __TOOLBAR_H + +#define tiBITMAP 1 +#define tiSEPARATOR 2 + +#define tfDISABLED 1 +#define tfDEPRESSED 0x8000 + +#define WC_MTOOLBAR "MToolBar" + +typedef struct { + ULONG ulType; + ULONG ulId; + ULONG ulCommand; + ULONG ulFlags; + HBITMAP hBitmap; +} ToolBarItem; + +typedef struct { + USHORT cb; + LONG ulCount; + ToolBarItem *pItems; + LONG ulDepressed; +} ToolBarData; + +MRESULT EXPENTRY ToolBarProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2); +void RegisterToolBarClass(HAB hab); +HWND CreateToolBar(HWND parent, + HWND owner, + ULONG id, + ULONG count, + ToolBarItem *items); + +#endif diff --git a/src/pmdlg.h b/src/pmdlg.h new file mode 100644 index 0000000..cc619f5 --- /dev/null +++ b/src/pmdlg.h @@ -0,0 +1,26 @@ +#define IDD_PROMPT 300 +#define IDS_PROMPT 301 +#define IDE_FIELD 302 + +#define IDD_FINDREPLACE 201 +#define IDD_FIND 202 + +#define IDL_FIND 211 +#define IDL_REPLACE 212 + +#define IDE_FIND 221 +#define IDE_REPLACE 222 + +#define IDC_IGNORECASE 231 +#define IDC_REGEXPS 232 +#define IDC_WORDS 233 +#define IDC_BLOCK 234 +#define IDC_GLOBAL 235 +#define IDC_REVERSE 236 +#define IDC_ALLOCCURENCES 237 +#define IDC_NOPROMPTING 238 +#define IDC_JOINLINE 239 +#define IDC_DELETELINE 240 + +#define IDD_FILEDLG 500 + diff --git a/src/pmdlg.rc b/src/pmdlg.rc new file mode 100644 index 0000000..6254932 --- /dev/null +++ b/src/pmdlg.rc @@ -0,0 +1,81 @@ +/* pmdlg */ + +#include "pmdlg.h" + +DLGTEMPLATE IDD_FIND +BEGIN + DIALOG "Find text...", IDD_FIND, 10, 13, 240, 79, WS_VISIBLE, FCF_SYSMENU | FCF_TITLEBAR + BEGIN + CONTROL "Find", IDL_FIND, 3, 66, 25, 8, WC_STATIC, SS_TEXT | DT_LEFT | DT_TOP | DT_MNEMONIC | WS_VISIBLE + CONTROL "", IDE_FIND, 37, 20, 198, 55, WC_COMBOBOX, CBS_DROPDOWN | LS_HORZSCROLL | WS_VISIBLE | WS_GROUP | WS_TABSTOP + CONTROL "Options", 101, 3, 21, 231, 42, WC_STATIC, SS_GROUPBOX | DT_LEFT | DT_TOP | DT_MNEMONIC | WS_VISIBLE | WS_GROUP + CONTROL "~Ignore Case", IDC_IGNORECASE, 9, 45, 75, 10, WC_BUTTON, BS_AUTOCHECKBOX | WS_VISIBLE | WS_GROUP | WS_TABSTOP + CONTROL "Rege~xps", IDC_REGEXPS, 9, 34, 77, 11, WC_BUTTON, BS_AUTOCHECKBOX | WS_VISIBLE + CONTROL "~Words only", IDC_WORDS, 9, 24, 74, 10, WC_BUTTON, BS_AUTOCHECKBOX | WS_VISIBLE + CONTROL "~Block", IDC_BLOCK, 86, 45, 60, 10, WC_BUTTON, BS_AUTOCHECKBOX | WS_VISIBLE + CONTROL "~Global", IDC_GLOBAL, 86, 35, 63, 10, WC_BUTTON, BS_AUTOCHECKBOX | WS_VISIBLE + CONTROL "~Reverse", IDC_REVERSE, 86, 25, 68, 10, WC_BUTTON, BS_AUTOCHECKBOX | WS_VISIBLE + CONTROL "~All occurences", IDC_ALLOCCURENCES, 155, 45, 72, 10, WC_BUTTON, BS_AUTOCHECKBOX | WS_VISIBLE + CONTROL "~Delete line", IDC_DELETELINE, 155, 35, 73, 10, WC_BUTTON, BS_AUTOCHECKBOX | WS_VISIBLE + CONTROL "~Join line", IDC_JOINLINE, 155, 25, 75, 10, WC_BUTTON, BS_AUTOCHECKBOX | WS_VISIBLE + DEFPUSHBUTTON "OK", DID_OK, 3, 3, 51, 14, BS_PUSHBUTTON | BS_DEFAULT | WS_VISIBLE | WS_GROUP | WS_TABSTOP + PUSHBUTTON "Cancel", DID_CANCEL, 58, 3, 51, 14 + END + +END + +DLGTEMPLATE IDD_FINDREPLACE +BEGIN + DIALOG "Find and replace...", IDD_FINDREPLACE, 9, 27, 240, 91, WS_VISIBLE, FCF_SYSMENU | FCF_TITLEBAR + BEGIN + CONTROL "Find", IDL_FIND, 4, 78, 29, 8, WC_STATIC, SS_TEXT | DT_LEFT | DT_TOP | DT_MNEMONIC | WS_VISIBLE + CONTROL "", IDE_FIND, 45, 21, 189, 67, WC_COMBOBOX, CBS_DROPDOWN | LS_HORZSCROLL | WS_VISIBLE | WS_GROUP | WS_TABSTOP + CONTROL "Replace", IDL_REPLACE, 4, 64, 35, 9, WC_STATIC, SS_TEXT | DT_LEFT | DT_TOP | DT_MNEMONIC | WS_VISIBLE | WS_GROUP + CONTROL "", IDE_REPLACE, 45, 12, 189, 63, WC_COMBOBOX, CBS_DROPDOWN | LS_HORZSCROLL | WS_VISIBLE | WS_GROUP | WS_TABSTOP + CONTROL "Options", 101, 4, 21, 232, 41, WC_STATIC, SS_GROUPBOX | DT_LEFT | DT_TOP | DT_MNEMONIC | WS_VISIBLE | WS_GROUP + CONTROL "~Ignore Case", IDC_IGNORECASE, 9, 45, 77, 10, WC_BUTTON, BS_AUTOCHECKBOX | WS_VISIBLE | WS_GROUP | WS_TABSTOP + CONTROL "Rege~xps", IDC_REGEXPS, 9, 34, 75, 11, WC_BUTTON, BS_AUTOCHECKBOX | WS_VISIBLE + CONTROL "~Words only", IDC_WORDS, 9, 24, 77, 10, WC_BUTTON, BS_AUTOCHECKBOX | WS_VISIBLE + CONTROL "~Block", IDC_BLOCK, 86, 45, 64, 10, WC_BUTTON, BS_AUTOCHECKBOX | WS_VISIBLE + CONTROL "~Global", IDC_GLOBAL, 86, 35, 64, 10, WC_BUTTON, BS_AUTOCHECKBOX | WS_VISIBLE + CONTROL "~Reverse", IDC_REVERSE, 86, 25, 68, 10, WC_BUTTON, BS_AUTOCHECKBOX | WS_VISIBLE + CONTROL "~All occurences", IDC_ALLOCCURENCES, 154, 45, 72, 10, WC_BUTTON, BS_AUTOCHECKBOX | WS_VISIBLE + CONTROL "~No prompting", IDC_NOPROMPTING, 154, 35, 72, 10, WC_BUTTON, BS_AUTOCHECKBOX | WS_VISIBLE + CONTROL "~Join Line", IDC_JOINLINE, 154, 25, 76, 10, WC_BUTTON, BS_AUTOCHECKBOX | WS_VISIBLE | WS_GROUP | WS_TABSTOP + DEFPUSHBUTTON "OK", DID_OK, 4, 3, 51, 14, BS_PUSHBUTTON | BS_DEFAULT | WS_VISIBLE | WS_GROUP | WS_TABSTOP + PUSHBUTTON "Cancel", DID_CANCEL, 59, 3, 51, 14 + END + +END + +DLGTEMPLATE IDD_PROMPT +BEGIN + DIALOG "", IDD_PROMPT, 6, 125, 198, 50, WS_VISIBLE, FCF_SYSMENU | FCF_TITLEBAR + BEGIN + CONTROL "", IDS_PROMPT, 3, 39, 192, 7, WC_STATIC, SS_TEXT | DT_LEFT | DT_TOP | DT_MNEMONIC | WS_VISIBLE | WS_GROUP + CONTROL "", IDE_FIELD, 4, 3, 191, 34, WC_COMBOBOX, CBS_DROPDOWN | WS_VISIBLE | WS_GROUP | WS_TABSTOP + DEFPUSHBUTTON "OK", DID_OK, 4, 3, 51, 14 + PUSHBUTTON "Cancel", DID_CANCEL, 59, 3, 51, 14 + END + +END + +DLGTEMPLATE IDD_FILEDLG +BEGIN + DIALOG "", IDD_FILEDLG, 11, -2, 242, 200, FS_DLGBORDER | WS_VISIBLE | WS_CLIPSIBLINGS | WS_SAVEBITS, FCF_TITLEBAR | FCF_SYSMENU + BEGIN + LTEXT "~Name", DID_FILENAME_TXT, 6, 189, 229, 8, SS_TEXT | DT_LEFT | DT_TOP | DT_MNEMONIC | WS_VISIBLE | NOT WS_GROUP + CONTROL "", DID_FILENAME_ED, 5, 143, 234, 45, WC_COMBOBOX, 2 | WS_VISIBLE | WS_GROUP | WS_TABSTOP + LTEXT "~Type of file:", DID_FILTER_TXT, 6, 168, 133, 8, SS_TEXT | DT_LEFT | DT_TOP | DT_MNEMONIC | WS_VISIBLE | WS_GROUP + CONTROL "", DID_FILTER_CB, 5, 102, 135, 65, WC_COMBOBOX, 4 | WS_VISIBLE | WS_GROUP | WS_TABSTOP + LTEXT "~Drive:", DID_DRIVE_TXT, 145, 168, 91, 8, SS_TEXT | DT_LEFT | DT_TOP | DT_MNEMONIC | WS_VISIBLE | WS_GROUP + CONTROL "", DID_DRIVE_CB, 143, 103, 95, 64, WC_COMBOBOX, 4 | WS_VISIBLE | WS_GROUP | WS_TABSTOP + LTEXT "~File:", DID_FILES_TXT, 125, 146, 114, 8, SS_TEXT | DT_LEFT | DT_TOP | DT_MNEMONIC | WS_VISIBLE | WS_GROUP + CONTROL "", DID_FILES_LB, 125, 23, 111, 120, WC_LISTBOX, WS_VISIBLE | WS_TABSTOP + LTEXT "Di~rectory:", DID_DIRECTORY_TXT, 5, 146, 110, 8, SS_TEXT | DT_LEFT | DT_TOP | DT_MNEMONIC | WS_VISIBLE | WS_GROUP + CONTROL "", DID_DIRECTORY_LB, 5, 23, 113, 120, WC_LISTBOX, LS_OWNERDRAW | WS_VISIBLE | WS_TABSTOP + CONTROL "Ok", DID_OK, 5, 4, 40, 14, WC_BUTTON, 1024 | WS_VISIBLE | WS_GROUP | WS_TABSTOP + CONTROL "Cancel", DID_CANCEL, 51, 4, 40, 14, WC_BUTTON, WS_VISIBLE | WS_TABSTOP + END + +END diff --git a/src/port.c b/src/port.c new file mode 100644 index 0000000..7ddc858 --- /dev/null +++ b/src/port.c @@ -0,0 +1,668 @@ +/* + * port.c: portable versions of often-used calls + * ================================================= + * (C)1996 by F.Jalvingh; Public domain. + * (C)1997 by Markus F.X.J. Oberhumer; Public domain. + * + * $Header: /cvsroot/fte/fte/src/port.c,v 1.1.1.1 2000/01/30 17:23:32 captnmark Exp $ + * + * $Log: port.c,v $ + * Revision 1.1.1.1 2000/01/30 17:23:32 captnmark + * initial import + * + */ + +#include "port.h" + +#ifndef MAXPATH +# define MAXPATH 256 +#endif + + +/****************************************************************************/ +/* */ +/* CODING: Windows NT portable calls. */ +/* */ +/****************************************************************************/ +#if defined(NT) + + +#define WIN32_LEAN_AND_MEAN +#include + +#include +#include +#include + + +/* + * plGetcurdir() returns the current directory for the drive specified. Drive + * 0=current, 1=a, 2=B etc. + */ +int plGetcurdir(int drive, char *dir) +{ + char tmp[256], t2[6], org[6]; + int rv; + + //** For NT: get current disk; then change to the requested one, and rest. + rv = -1; + GetCurrentDirectory(sizeof(tmp), tmp); // Get current disk & dir; + assert(tmp[1] == ':'); + if(drive == 0) // Is current drive? + { + strcpy(dir, tmp+3); // Copy all after C:\ to dir, + rv = 0; + } + else + { + strncpy(org, tmp, 2); // Copy : + org[2] = 0; + + //** Move to the required drive, + *t2 = drive + 'A'-1; // Form drive letter. + strcpy(t2+1, ":"); + if(! SetCurrentDirectory(t2)) return -1;// Try to move there; + if(GetCurrentDirectory(sizeof(tmp), tmp)) + { + strcpy(dir, tmp+3); // Copy to result, + rv = 0; + } + + SetCurrentDirectory(org); // Move back to original.. + } + return rv; +} + + +int plGetdisk(void) +{ + char buf[256]; + int d; + + GetCurrentDirectory(sizeof(buf), buf); + d = toupper(*buf) - 'A'; // 0=A, 1=B, etc. + if(d < 0 || d > 25) return -1; + return d; +} + +int plSetdisk(int drive) +{ + char buf[30]; + + if( drive < 0 || drive > 25) return -1; + *buf = drive + 'A'; + strcpy(buf+1, ":"); + return SetCurrentDirectory(buf) ? 0 : -1; +} + + +/****************************************************************************/ +/* */ +/* CODING: OS/2 portable calls. */ +/* */ +/****************************************************************************/ +#elif defined(OS2) +#define __32BIT__ 1 + +#define INCL_BASE +#define INCL_DOSMISC +#define INCL_DOS +#define INCL_SUB +#define INCL_DOSERRORS +#define INCL_DOSFILEMGR +#define INCL_NOPMAPI +#include + + +/* + * plGetcurdir() returns the current directory for the drive specified. + */ +int plGetcurdir(int drive, char *dir) +{ +#ifdef __32BIT__ + ULONG bytes; + + bytes = 0; + DosQueryCurrentDir(drive, NULL, &bytes); + if(bytes > MAXPATH) return -1; + DosQueryCurrentDir(drive, dir, &bytes); + return 0; +#else + USHORT bytes; + + bytes = 0; + DosQCurDir(drive, NULL, &bytes); + if(bytes > MAXPATH) return -1; + DosQCurDir(drive, dir, &bytes); + return 0; +#endif +} + + +/* + * plGetdisk() returns the current disk's number. A=0, B=1 etc. + */ +int plGetdisk(void) +{ +#ifdef __32BIT__ + ULONG drive, numdrives; + + DosQueryCurrentDisk(&drive, &numdrives); +#else + USHORT drive; + ULONG numdrives; + + DosQCurDisk(&drive, &numdrives); +#endif + return (int)drive - 1; + +} + + +/* + * plSetdisk() makes another drive the current drive. Use A=0, B=1 etc. It + * returns 0 on succes. + */ +int plSetdisk(int drive) +{ +#if defined(__32BIT__) + return (int)DosSetDefaultDisk((ULONG)drive + 1); +#else + return (int)DosSelectDisk((USHORT)drive + 1); /* Bcc getdisk: 'A' = 0; MSC DosSelectdisk: 'A' = 1 */ +#endif +} + + +/****************************************************************************/ +/* */ +/* CODING: DOS Extender code - basic functionality & interrupt calls. +*/ /* */ +/****************************************************************************/ +#elif defined(DOSP32) + +/* + * The following code is used to handle DOS-specific calls and memory from + * within several DOS extender(s), or from plain DOS. To compile for other + * DOS extenders simply recode the base calls; the extended calls are defined + * in terms of the base calls. + * + * Currently the following implementations exist: + * - Dos4GW i.c.m. the Watcom C compiler + * - djgpp v2 + */ + +/*--------------------------------------------------------------------------*/ +/* CODING: 32-bits protected mode DOS with DOS4GW and Watcom C++. */ +/*--------------------------------------------------------------------------*/ +#if defined(__DOS4G__) // Defined when compiled with Watcom for Dos4GW +#include + +#define HIWORD(x) ( (UWORD) ((x) >> 16)) +#define LOWORD(x) ( (UWORD) (x)) + + +/* + * dosxIntr() does a 16-bit interrupt with translation for the extender. It + * is used to call DOS and BIOS interrupts from within C. + */ +void dosxIntr(int inr, union dosxReg* r) +{ + union REGPACK rp; + + //** Convert the parameters to a REGPACK structure, + rp.x.eax = r->x.eax; rp.x.ebx = r->x.ebx; rp.x.ecx = r->x.ecx; + rp.x.edx = r->x.edx; rp.x.esi = r->x.esi; rp.x.edi = r->x.edi; + rp.x.ds = r->x.ds; rp.x.es = r->x.es; rp.x.fs = r->x.fs; rp.x.gs = r->x.gs; + rp.x.flags = r->x.flags; + intr(inr, &rp); + + //** And translate back.. + r->x.eax = rp.x.eax; r->x.ebx = rp.x.ebx; r->x.ecx = rp.x.ecx; + r->x.edx = rp.x.edx; r->x.esi = rp.x.esi; r->x.edi = rp.x.edi; + r->x.ds = rp.x.ds; r->x.es = rp.x.es; r->x.fs = rp.x.fs; r->x.gs = rp.x.gs; + r->x.flags = rp.x.flags; +} + + +/* + * The Dos4GW extender maps the DOS memory arena (the 1st 1Mb of physical + * memory) to the 1st MB of extender memory. So, to access 0040:0087 in the + * BIOS data segment we use the linear address 0x487. + * + * The memory routines translate the seg:off address passed to a linear + * address. + */ + + +/* + * SegToPhys() converts an address in seg:off format to a physical address. + */ +static void* SegToPhys(ULONG ra) +{ + return (void*) ( ((ULONG) HIWORD(ra) << 4) + (ULONG)LOWORD(ra)); } + + +/* + * dosxMemRead() reads the specified #bytes from the DOS real memory to the + * buffer specified. The address is specified as a seg:off address (even + * in extended mode); it is translated to the appropriate physical address. + */ +void dosxMemRead(void* dest, ULONG ra, unsigned nbytes) +{ + memcpy(dest, SegToPhys(ra), nbytes); +} + + +/* + * dosxMemWrite() writes the specified #bytes to DOS real memory. is in + * seg:off format. + */ +void dosxMemWrite(ULONG ra, void* src, unsigned nbytes) +{ + memcpy(SegToPhys(ra), src, nbytes); +} + + +/* + * dosxPMemRead() reads the specified #bytes from physical memory to the + * buffer specified. The physical address is the linear address, not a + * segmented one! + */ +void dosxPMemRead(void* dest, ULONG pa, unsigned nbytes) +{ + memcpy(dest, (void*) pa, nbytes); +} + + +/* + * dosxPMemWrite() writes the specified #bytes to physical memory. + */ +void dosxPMemWrite(ULONG pa, void* src, unsigned nbytes) +{ + memcpy((void*) pa, src, nbytes); +} + + +#elif defined(__DJGPP__) + +#include +#include +#include +#include +#include +#include + +/* + * dosxIntr() does a 16-bit interrupt with translation for the extender. It + * is used to call DOS and BIOS interrupts from within C. + */ +void dosxIntr(int inr, union dosxReg* r) +{ + __dpmi_regs rp; + + //** Convert the parameters to a REGPACK structure, + rp.d.eax = r->x.eax; rp.d.ebx = r->x.ebx; rp.d.ecx = r->x.ecx; + rp.d.edx = r->x.edx; rp.d.esi = r->x.esi; rp.d.edi = r->x.edi; + rp.x.ds = r->x.ds; rp.x.es = r->x.es; rp.x.fs = r->x.fs; rp.x.gs = r->x.gs; + rp.x.flags = r->x.flags; + __dpmi_int(inr, &rp); + + //** And translate back.. + r->x.eax = rp.d.eax; r->x.ebx = rp.d.ebx; r->x.ecx = rp.d.ecx; + r->x.edx = rp.d.edx; r->x.esi = rp.d.esi; r->x.edi = rp.d.edi; + r->x.ds = rp.x.ds; r->x.es = rp.x.es; r->x.fs = rp.x.fs; r->x.gs = rp.x.gs; + r->x.flags = rp.x.flags; +} + + +/* + * dosxMemRead() reads the specified #bytes from the DOS real memory to the + * buffer specified. The address is specified as a seg:off address (even + * in extended mode); it is translated to the appropriate physical address. + */ +void dosxMemRead(void* dest, ULONG ra, unsigned nbytes) +{ + unsigned x = ((ra & 0xffff0000) >> 12) + (ra & 0xffff); + movedata(_dos_ds, x, _my_ds(), (unsigned) dest, nbytes); +} + + +/* + * dosxMemWrite() writes the specified #bytes to DOS real memory. is in + * seg:off format. + */ +void dosxMemWrite(ULONG ra, void* src, unsigned nbytes) +{ + unsigned x = ((ra & 0xffff0000) >> 12) + (ra & 0xffff); + movedata(_my_ds(), (unsigned) src, _dos_ds, x, nbytes); +} + + +/* + * dosxPMemRead() reads the specified #bytes from physical memory to the + * buffer specified. The physical address is the linear address, not a + * segmented one! + */ +void dosxPMemRead(void* dest, ULONG pa, unsigned nbytes) +{ + assert(0); /* not used */ +} + + +/* + * dosxPMemWrite() writes the specified #bytes to physical memory. + */ +void dosxPMemWrite(ULONG pa, void* src, unsigned nbytes) +{ + assert(0); /* not used */ +} + + + +#else // Not Dos4GW or djgpp +# error "Extender type not defined/illegal extender type." +#endif + + +/* + * dosxDisable() disables interrupts. + */ +void dosxDisable(void) +{ +#if defined(__WATCOMC__) || defined(__MSC__) + _disable(); +#elif defined(__DJGPP__) + __asm__ __volatile__("cli \n"); +#else + disable(); +#endif +} + +/* + * dosxEnable() enables interrupts. + */ +void dosxEnable(void) +{ +#if defined(__WATCOMC__) || defined(__MSC__) + _enable(); +#elif defined(__DJGPP__) + __asm__ __volatile__("sti \n"); +#else + enable(); +#endif +} + + +/****************************************************************************/ +/* */ +/* CODING: DOS-based portability calls. */ +/* */ +/****************************************************************************/ +#ifdef __WATCOMC__ +#include +#endif +#include + + +/* + * plGetcurdir() returns the current directory for the drive specified. Drive + * 0=a, 1=B etc. + */ +int plGetcurdir(int drive, char *dir) +{ + union dosxReg r; + +#if defined(__32BIT__) && !defined(__DJGPP__) + void far *ptr; +#endif + + memset(&r, 0, sizeof(r)); + r.w.ax = 0x4700; // Get current directory + r.h.dl = drive; // Get drive (0=current, 1=a etc)!! +#if defined(__DJGPP__) + r.w.ds = _my_ds(); + r.x.esi = (unsigned) dir; // Pass the address of the buffer. +#elif defined(__32BIT__) + ptr = dir; // Get full 16:32 address of dir, + r.w.ds = FP_SEG(ptr); + r.x.esi = FP_OFF(dir); // Pass the address of the buffer. +#else + r.w.ds = FP_SEG(dir); + r.w.si = FP_OFF(dir); +#endif + dosxIntr(0x21, &r); + return r.x.flags & 0x80 ? -1 : 0; // Carry flag is set? +} + + +#if defined(__WATCOMC__) || defined(__DJGPP__) + +int plSetdisk(int drive) +{ + unsigned ndr; + + _dos_setdrive(drive +1, &ndr); + return 0; +} + +int plGetdisk(void) +{ + unsigned drv; + + _dos_getdrive(&drv); + return drv - 1; +} + +#elif defined(__BORLANDC__) +int plSetdisk(int drive) +{ + return setdisk(drive); +} + +int plGetdisk(void) +{ + return getdisk(); +} + +#else +# error "Undefined compiler for DOS/Extended DOS" +#endif + + + +#else +# error "Platform not supported." +#endif + + +/****************************************************************************/ +/* */ +/* CODING: an implementation of fnmatch(), when needed... */ +/* */ +/****************************************************************************/ +#if (defined(NT) || defined(DOSP32)) && !defined(__DJGPP__) +/* + * Wildcard spec's: + * ================ + * + * * matches 0-n characters, so * only removes all. + * ? matches any character on that position. + * #c matches 0-n occurences of the character c. Note: #? is the same + * as *. + * a+b Matches either a or b. a and b may be complex expressions. + * () Keep expressions together, + * + * Examples: + * --------- + * *.(obj+lib+exe) Matches *.exe, *.lib and *.exe. + * t#a.* Matches t.*, ta.* taa.* etc + * + * Small grammar: + * ============== + * pattern: + */ +#define ENDCH(x) ((x) == '+' || (x) == ')' || (x) == 0) + +static int wcMatch(char **pval, char **pw); + +/* + * Next() moves to the next in the pattern, taking care of ( and ). + * It returns a nonzero value in case of error (bad match). + */ +static int Next(char **pptr, char ch) +{ + int braces; + + braces = 0; + for(;;) + { + switch(**pptr) + { + case 0: + if(braces == 0) + return 0; /* 0 always allowed if not in () */ + else + return ')'; /* Missing close brace! */ + + case '(': + braces++; + break; + + case ')': + if(braces == 0) + { + if(ch == ')' || ch == '+') + return 0; + else + return '('; /* Missing open brace */ + } + braces--; + break; + + default: + if(**pptr == ch && braces == 0) return 0; + } + *pptr += 1; + } +} + + +/* + * wcOrs() traverses + + .. + */ +static int wcOrs(char **pval, char **pw) +{ + char *vsave; + int res; + + for(;;) /* For each orred part, */ + { + vsave = *pval; /* Save current string, */ + res = wcMatch(pval, pw); /* Match part, */ + if(res != 0) return res; /* Exit if OK or error. */ + *pval = vsave; /* Back to start of string to match */ + + /**** Match not found. Find next ORred item, ****/ + res = Next(pw, '+'); + if(res > 0) return res; + if(**pw == 0 || **pw == ')') return 0; /* Exit if at eo$ */ + if(**pw != '+') return '+'; /* Expected | ?? */ + *pw += 1; + } +} + + + + +/* + * wcMatch() compares the string to match in *pval with the wildcard + * part in *pw. It returns True as soon as a match is found, and False + * if a match could not be found. + */ +static int wcMatch(char **pval, char **pw) +{ + char *vsave, *wsave; + int res; + + for(;;) + { + vsave = *pval; /* Saved string, */ + switch(*(*pw)++) + { + case '+': + case ')': + case 0: + /**** End of wildcarded string. If string is at end too ****/ + /**** match is found... ****/ + *pw -= 1; /* Back to terminator, */ + return **pval == 0; + + case '?': + /**** Match-anything.. ****/ + if(**pval == 0) return FALSE; /* Exhausted! No match */ + *pval += 1; /* Match one character, */ + break; /* And loop, */ + + case '(': + res = wcOrs(pval, pw); /* OR sequence valid? */ + if(res == 1) /* 1 -> Matched! */ + { + /**** OR sequence valid! Move to closing ) ****/ + res = Next(pw, ')'); /* Move past OR-sequence */ + if(res) return res; /* If error return, */ + if(**pw != ')') return ')'; /* Missing ')' !! */ + *pw += 1; /* Past ), */ + } + else + return res; /* Not found or Error!! */ + break; + + case '*': + /**** 0-n (kleene closure) any-character matches.. ****/ + while(**pval != 0) /* While not at end of user $ */ + { + /**** Compare current part of user string with what's ****/ + /**** left of the wildcards... ****/ + wsave = *pw; /* Get current wildcard ptr, after * */ + vsave = *pval; /* And to current part of $ */ + res = wcMatch(pval, pw); /* Check if $ matches, */ + if(res != 0) return res; /* Exit if matches or error, */ + *pw = wsave; /* Back wildcards, */ + *pval = vsave+1; /* Back user $ one pos further, */ + } + return ENDCH(**pw); /* No match. */ + + default: + if(toupper(**pval) != toupper(*(*pw - 1))) + { + *pw -= 1; + return 0; + } + *pval += 1; + break; + } + } +} + + +/* + * strCmpWild() returns -1 on wildcard error, 0 on match and 1 on no +match. + */ +int strCmpWild(char *val, char *wild) +{ + return wcOrs(&val, &wild); +} + + +/* + * fnmatch() does a wildcarded match. + */ +int fnmatch(char* pat, char* in, int vv) +{ + return strCmpWild(in, pat) == 1 ? 0 : 1; +} +#endif // fnmatch() + + + diff --git a/src/port.h b/src/port.h new file mode 100644 index 0000000..6dec6f1 --- /dev/null +++ b/src/port.h @@ -0,0 +1,291 @@ +#ifndef __port_port_h +#define __port_port_h + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef ULONG +# define ULONG unsigned long +#endif + +#ifndef UWORD +# define UWORD unsigned short +#endif + +#ifndef UBYTE +# define UBYTE unsigned char +#endif + +#ifndef boolean +# define boolean int +#endif + +#ifndef FALSE +# define FALSE 0 +#endif + +#ifndef TRUE +# define TRUE 1 +#endif + + + +/*--------------------------------------------------------------------------*/ +/* STRUCTURES: dosxEreg is a union containing all extended registers.. */ +/*--------------------------------------------------------------------------*/ +#if defined(__32BIT__) + #define __FILLER(a) unsigned short a; +#else + #define __FILLER(a) +#endif + +struct dosxEreg { + unsigned long eax, ebx, ecx, edx, ebp, esi, edi; + unsigned short ds, es, fs, gs; + unsigned long flags; +}; + +struct dosxBreg { + unsigned char al, ah; __FILLER(_1) + unsigned char bl, bh; __FILLER(_2) + unsigned char cl, ch; __FILLER(_3) + unsigned char dl, dh; __FILLER(_4) +}; + +struct dosxWreg { + unsigned short ax; __FILLER(_1) + unsigned short bx; __FILLER(_2) + unsigned short cx; __FILLER(_3) + unsigned short dx; __FILLER(_4) + unsigned short bp; __FILLER(_5) + unsigned short si; __FILLER(_6) + unsigned short di; __FILLER(_7) + unsigned short ds; + unsigned short es; + unsigned short fs; + unsigned short gs; + unsigned long flags; +}; + +/*--------------------------------------------------------------------------*/ +/* STRUCTURES: dosxReg contains all usable registers. */ +/*--------------------------------------------------------------------------*/ +union dosxReg { + struct dosxBreg h; + struct dosxWreg w; + struct dosxEreg x; +}; + + +/*--------------------------------------------------------------------------*/ +/* DEFINES: PLRF_* defines are the processor flags. */ +/*--------------------------------------------------------------------------*/ +#define PLCPUF_C 0x0001 // Carry flag +#define PLCPUF_P 0x0004 // Parity +#define PLCPUF_A 0x0010 // Auxiliary carry +#define PLCPUF_Z 0x0040 // Zero flag, +#define PLCPUF_S 0x0080 // Sign flag +#define PLCPUF_T 0x0100 // Trace flag +#define PLCPUF_I 0x0200 // Interrupt +#define PLCPUF_D 0x0400 // Direction +#define PLCPUF_O 0x0800 // Overflow. + + +/*--------------------------------------------------------------------------*/ +/* DEFINES: plFnsplit() defines. */ +/*--------------------------------------------------------------------------*/ +#define PL_WILDCARDS 0x01 +#define PL_EXTENSION 0x02 +#define PL_FILENAME 0x04 +#define PL_DIRECTORY 0x08 +#define PL_DRIVE 0x10 + +/*--------------------------------------------------------------------------*/ +/* DEFINES: File attributes. */ +/*--------------------------------------------------------------------------*/ +#define PLFA_NORMAL 0x00 /* Normal file, no attributes */ +#define PLFA_RDONLY 0x01 /* Read only attribute */ +#define PLFA_HIDDEN 0x02 /* Hidden file */ +#define PLFA_SYSTEM 0x04 /* System file */ +#define PLFA_LABEL 0x08 /* Volume label */ +#define PLFA_DIREC 0x10 /* Directory */ +#define PLFA_ARCH 0x20 /* Archive */ + + +/*--------------------------------------------------------------------------*/ +/* STRUCTURES: plFTime holds date/time for a file (plGetftime()). */ +/*--------------------------------------------------------------------------*/ +struct plFTime +{ + unsigned ft_tsec : 5; // Two second interval + unsigned ft_min : 6; // Minute + unsigned ft_hour : 5; // Hour + unsigned ft_day : 5; // Day + unsigned ft_month : 4; // Month + unsigned ft_year : 7; // Year +}; + + +/*--------------------------------------------------------------------------*/ +/* STRUCTURES: plDFree holds "disk free space" info for plGetdfree(). +*/ +/*--------------------------------------------------------------------------*/ +struct plDFree +{ + unsigned df_avail; + unsigned df_total; + unsigned df_bsec; + unsigned df_sclus; +}; + + +/*--------------------------------------------------------------------------*/ +/* DEFINES: plLocking() mode flags... */ +/*--------------------------------------------------------------------------*/ +#define PL_LK_UNLCK 0 // unlock the file region +#define PL_LK_LOCK 1 // lock the file region +#define PL_LK_NBLCK 2 // non-blocking lock +#define PL_LK_RLCK 3 // lock for writing +#define PL_LK_NBRLCK 4 // non-blocking lock for writing + + + +//** Hardware interface: DOS & extended DOS only!! +void dosxIntr(int inr, union dosxReg* r); + +void dosxMemRead(void* dest, ULONG ra, unsigned nbytes); +void dosxMemWrite(ULONG ra, void* src, unsigned nbytes); +void dosxPMemRead(void* dest, ULONG pa, unsigned nbytes); +void dosxPMemWrite(ULONG pa, void* src, unsigned nbytes); + +void dosxDisable(void); +void dosxEnable(void); + +//** Disk stuff.. +int plGetdisk(void); +int plSetdisk(int dnr); +int plGetcurdir(int drive, char *dir); + +//** Misc.. +char *plSearchpath(char *name); +int plFnsplit(const char *pathp, char *drivep, char *dirp, char *namep, +char *extp); void plFnmerge(char *out, char *drive, char *dir, char *name, +char *ext); + + +/****************************************************************************/ +/* */ +/* Hardware portability calls. */ +/* */ +/****************************************************************************/ + +//** Mouse calls +//** =========== +boolean MOUSInit(void); +void MOUSExit(void); +void MOUSCursen(boolean enable); +void MOUSPos(UWORD *x, UWORD *y, boolean *leftbutton, boolean +*rightbutton); void MOUSSetpos(UWORD x, UWORD y); +void MOUSSetTextCursor(UWORD screenmask, UWORD cursormask); +void MOUSSaveCurs(void); +void MOUSRestCurs(void); +boolean MOUSIsPresent(void); +ULONG MOUSPressCount(void); + +//** Timer calls +//** =========== +int plTiAlloc(unsigned long cnt); +void plTiSet(int t, unsigned long cnt); +void plTiFree(int t); +unsigned long plTiQValue(int t); + +//** Thread/task based. +//** ================== +void plDelay(unsigned int msecs); +unsigned long plTmGet(void); // Avoid using this. +void plCpuRelease(void); + + +//** Thread interface! +//** ================= +int plThrdStart(void (*exfn)(void*), unsigned long stksz, void* args); + + +//** FTE specific. +int fnmatch(char* pat, char* in, int vv); + + +#ifdef DOSP32 + +/*--------------------------------------------------------------------------*/ +/* ENUM: ePlScnType defines a screen type. */ +/*--------------------------------------------------------------------------*/ +enum ePlScnType +{ + plsctUnknown, + plsctMono, // Monochrome adapter / unknown type, + plsctCGA, // Color graphics adapter + plsctEGA, // EGA adapter, + plsctVGA, // VGA adapter, + plsctLast +}; + + +//** Informational functions, +enum ePlScnType plScnType(void); +boolean plScnIsMono(void); +int plScnWidth(void); +int plScnHeight(void); +void plScnCursorShapeGet(int* sp, int* ep); +void plScnCursorPosGet(int* xp, int* yp); + + +//** Change parameters e.a. +void plScnSetFlash(boolean on); +void plScnCursorOn(boolean on); +void plScnCursorShape(int start, int end); +void plScnCursorPos(int x, int y); + + +//** Writing the screen. +void plScnWrite(unsigned x, unsigned y, unsigned short* buf, unsigned nch); +void plScnRead(unsigned x, unsigned y, unsigned short* buf, unsigned nch); +void plScnSetCell(unsigned x, unsigned y, unsigned wid, unsigned hig, UWORD cell); +void plScnScrollDown(int x, int y, int ex, int ey, int nlines, UWORD fill); +void plScnScrollUp(int x, int y, int ex, int ey, int nlines, UWORD fill); + + +/****************************************************************************/ +/* */ +/* Keyboard interface.. */ +/* */ +/****************************************************************************/ +struct plKbdInfo +{ + UBYTE ki_scan; + UBYTE ki_ascii; + ULONG ki_flags; // PLKF_ defines, above; +}; + +#define PLKF_SHIFT 0x0001 +#define PLKF_CTRL 0x0002 +#define PLKF_ALT 0x0004 +#define PLKF_SCROLLLOCK 0x0008 +#define PLKF_NUMLOCK 0x0010 +#define PLKF_CAPSLOCK 0x0020 + + +boolean plKbdReadF(struct plKbdInfo* ki); + + +#endif + + +#ifdef __cplusplus +}; +#endif + + +#endif + diff --git a/src/portdos.c b/src/portdos.c new file mode 100644 index 0000000..3b0d428 --- /dev/null +++ b/src/portdos.c @@ -0,0 +1,960 @@ +/* + * portdos.c: Portable calls for DOS + * ================================== + * (C)1996 by F.Jalvingh; Public domain. + * (C)1997 by Markus F.X.J. Oberhumer; Public domain. + * + * $Header: /cvsroot/fte/fte/src/portdos.c,v 1.1.1.1 2000/01/30 17:23:45 captnmark Exp $ + * + * $Log: portdos.c,v $ + * Revision 1.1.1.1 2000/01/30 17:23:45 captnmark + * initial import + * + */ +#include "port.h" +#include +#include + +#if defined(DOS) || defined(DOSP32) +#include +#if defined(__DJGPP__) +#include +#include +#include +#include +#define inp inportb +#define outp outportb +#endif + +struct plScnInfo +{ + int s_inited; // T when current status is known. + int s_wid, s_hig; // Current screen size + enum ePlScnType s_type; // Current screen type, + boolean s_ismono; // T when black- and white. + boolean s_isbright; + + //** Cursor info, + boolean s_curinit; + boolean s_curon; // T when cursor is visible + int s_cur_x, s_cur_y; // Current cursor position, + int s_curstart, // Start of cursor blob, + s_curend; // End of blob; + + + UWORD s_iobase; + +#if defined(__DOS4G__) || defined(__DJGPP__) + ULONG s_pbase; // Physical base address of video memory +#else + UWORD s_pseg; // Segment of video memory +#endif +}; + + +/*--------------------------------------------------------------------------*/ +/* STATIC GLOBALS.. */ +/*--------------------------------------------------------------------------*/ +static struct plScnInfo plScnI; +static void plScnInit(void); + + +/* + * between() returns a # between bounds. + */ +static int between(int x, int low, int hig) +{ + if(x < low) + return low; + else if(x > hig) + return hig; + return x; +} + + +/****************************************************************************/ +/* */ +/* CODING: Screen type determination for DOS.. */ +/* */ +/****************************************************************************/ +/* + * This is very important for the working of the DOS interface. It determines + * the screen type, and derives some stuff from that: + * - screen base address (i/o port) + * - video memory address (for direct I/O to the screen). + */ +/* + * VgaMonoMonitor() returns T if the monitor attached to a VGA adaptor is a + * monochrome monitor. + */ +static boolean VgaMonoMonitor(void) +{ + union dosxReg r; + + memset(&r, 0, sizeof(r)); // Clear all unused regs, + r.w.ax = 0x1a00; // Function 1A subfunction 00 + dosxIntr(0x10, &r); // Call VGA BIOS, + if(r.h.al != 0x1a) return FALSE; // Assume color if call not supported, + if(r.h.bl == 0x01 || r.h.bl == 0x05 || r.h.bl == 0x07 ||r.h.bl == 0x0B) + return TRUE; // These types are MONO, + else + return FALSE; +} + + +/* + * biosisVGA() returns TRUE if a VGA-card is found. + */ +static boolean biosisVGA(void) +{ + boolean isvga; + + outp(0x3ce, 8); // Bit mask register, + outp(0x3cf, 1); // Test mask, (1) + outp(0x3ce, 8); // Bit mask register again, + if(inp(0x3cf) == 1) // Can we read the same value? + isvga = TRUE; // Yes -> is VGA! + else + isvga = FALSE; + outp(0x3ce, 8); // Bit mask register last time, + outp(0x3cf, 0xff); // All on (default value) + return isvga; +} + + +/* + * biosisEGA() returns TRUE if the card is an EGA card (or a VGA card). + */ +static boolean biosisEGA(void) +{ + union dosxReg r; + UBYTE ega; + + //** Get EGA BIOS byte. + dosxMemRead(&ega, 0x00400087ul, 1); // Read EGA BIOS sysvar, + if(! (ega & 0x08)) // There's an active EGA in the system! + { + //** EGA is active: do EGA bios call.. + memset(&r, 0, sizeof(r)); + r.h.ah = 0x12; // EGA BIOS Get info, + r.h.bl = 0x10; // Get info + r.h.bh = 0xff; // Inpossible return value, + dosxIntr(0x10, &r); // Call EGA BIOS, + if(r.h.bh != 0xff) // EGA found? + return TRUE; // Yes! + } + return FALSE; +} + + +/* + * biosisMono() returns TRUE if the BIOS is currently in MONO mode. This + * is the mode selected with the MODE co80 or MODE MONO command. For EGA and + * VGA cards this mode doesn't tell a thing about the MONITOR attached!!! + */ +static boolean biosisMono(void) +{ + union dosxReg r; + + //** Call the BIOS get video mode + memset(&r, 0, sizeof(r)); + r.w.ax = 0x0f00; + dosxIntr(0x10, &r); + r.h.al &= 0x7f; // Mask out DONT-CLEAR bit, + if(r.h.al == 7) return TRUE; // Monochrome screen + if(r.h.al == 2 || r.h.al == 3) return FALSE;// Color screen, + return TRUE; // All else: return MONO +} + + +/* + * getPrimaryType() returns the primary card type. + */ +static enum ePlScnType getPrimaryType() +{ + if(biosisEGA()) // Minimal EGA? + return biosisVGA() ? plsctVGA : plsctEGA; + return biosisMono() ? plsctMono : plsctCGA; +} + + +/* + * getType() determines the screen type. + */ +static void getType(void) +{ + enum ePlScnType sct; + + sct = getPrimaryType(); // Get primary screen type; + switch(sct) + { + default: plScnI.s_ismono = biosisMono(); break; + case plsctVGA: plScnI.s_ismono = VgaMonoMonitor(); break; + } + + //** Determine hardware addresses.. +#if defined(__DJGPP__) + plScnI.s_pbase = ScreenPrimary; +#elif defined(__DOS4G__) + plScnI.s_pbase = plScnI.s_ismono ? 0xb0000 : 0xb8000; +#elif defined(__MSDOS__) + plScnI.s_pseg = plScnI.s_ismono ? 0xb000 : 0xb800; +#endif + plScnI.s_iobase = plScnI.s_ismono ? 0x3b4 : 0x3d4; + plScnI.s_type = sct; +} + + +/****************************************************************************/ +/* */ +/* CODING: Screen - Other base helper calls.. */ +/* */ +/****************************************************************************/ +/* + * getSize() inquires the BIOS about the screen size. + */ +static void getSize(void) +{ + union dosxReg r; + + //** Get the current width of the screen, + memset(&r, 0, sizeof(r)); + r.w.ax = 0x0f00; // Get current video mode, + dosxIntr(0x10, &r); // Video BIOS + plScnI.s_wid = between(r.h.ah, 80, 256); + + if(plScnI.s_type < plsctEGA) // For all lower as EGA use 25 height + plScnI.s_hig = 25; + else + { + r.w.ax = 0x1130; // Get FONT information, + r.w.bx = 0; + dosxIntr(0x10, &r); + r.h.dl += 1; // For some reason it reports 1 too small, + plScnI.s_hig = between(r.h.dl, 25, 128); + } +} + + +/* + * getCurInfo() gets the current cursor info: position and shape, visibility. + */ +static void getCurInfo(void) +{ + union dosxReg r; + + //** Ask the BIOS for the current cursor shape, + memset(&r, 0, sizeof(r)); + r.w.ax = 0x0300; // Get cursor shape, + r.w.bx = 0; // Page 0 + dosxIntr(0x10, &r); + plScnI.s_cur_x = r.h.dl; + plScnI.s_cur_y = r.h.dh; + plScnI.s_curstart = r.h.ch; + plScnI.s_curend = r.h.cl; + if(! plScnI.s_curinit) // Cursor state not initialized? + { + plScnI.s_curon = TRUE; // Default to cursor ON, + plScnI.s_curinit= TRUE; + } +} + + +/* + * plScnInit() is called to get most of the info required to do screen I/O. + * Depending on the "inited" flag it will get the current screen size, the + * mode, cursor shape and visibility etc. + */ +static void plScnInit(void) +{ + if(plScnI.s_inited) return; // Exit immediately if already inited, + getType(); // ALWAYS get TYPE 1st! + getSize(); // Get current mode (screen size) + getCurInfo(); + plScnI.s_inited = TRUE; // Don't init again. +} + + +/* + * plScnSetFlash() is called to SET/CLEAR the flash/bright indicator. + */ +void plScnSetFlash(boolean on) +{ + union dosxReg r; + + memset(&r, 0, sizeof(r)); + r.w.ax = 0x1003; + r.w.bx = on ? 1 : 0; // Set HILITE or FLASH mode. + dosxIntr(0x10, &r); + plScnI.s_isbright = !on; // Set ISBRIGHT mode flag. +} + + +#if defined(__DJGPP__) +static void ScreenSetCursorShape(int shape) +{ + __dpmi_regs reg; + + reg.h.ah = 0x01; + reg.h.al = ScreenMode(); + reg.x.cx = shape & 0x7f1f; + __dpmi_int(0x10, ®); +} +#else +/* + * cardOut().. + */ +static void cardOut(int port, int val) +{ + outp(plScnI.s_iobase, port); + outp(plScnI.s_iobase + 1, val); +} +#endif + + +/* + * plScnCursorOn() switches the cursor ON or OFF. + */ +void plScnCursorOn(boolean on) +{ + UWORD v; + + plScnInit(); + + plScnI.s_curon = on; + v = (UWORD) ( ((plScnI.s_curstart & 0xff) << 8) | (plScnI.s_curend & 0xff)); + if(! on) v |= 0x2000; // Disable if required.. + +#if defined(__DJGPP__) + ScreenSetCursorShape(v); +#else + dosxDisable(); + cardOut(10, v >> 8); + cardOut(11, v & 0xff); + + if(! on) + { + cardOut(14, 20); + cardOut(15, 0); + } + dosxEnable(); +#endif +} + + +/* + * plScnCursorShape() sets the cursor shape. + */ +void plScnCursorShape(int start, int end) +{ + plScnInit(); + plScnI.s_curstart = start; + plScnI.s_curend = end; + + plScnCursorOn(plScnI.s_curon); // Switch cursor on/off; sets shape. +} + + +/* + * plScnCursorShapeGet() + */ +void plScnCursorShapeGet(int* sp, int* ep) +{ + getCurInfo(); + *sp = plScnI.s_curstart; + *ep = plScnI.s_curend; +} + + +/* + * plScnCursorPos() sets the cursor's position. + */ +void plScnCursorPos(int x, int y) +{ +#if defined(__DJGPP__) + ScreenSetCursor(y,x); +#else + UWORD soff; + + plScnInit(); + + soff= (UWORD) (y * plScnI.s_wid + x); + dosxDisable(); + cardOut(14, (soff >> 8)); + cardOut(15, soff & 0xff); + dosxEnable(); + plScnI.s_cur_x = x; + plScnI.s_cur_y = y; +#endif +} + + +/* + * plScnCursorPosGet() + */ +void plScnCursorPosGet(int* xp, int* yp) +{ +// getCurInfo(); + *xp = plScnI.s_cur_x; + *yp = plScnI.s_cur_y; +} + + + +/****************************************************************************/ +/* */ +/* DJGPP implementation. */ +/* */ +/****************************************************************************/ +#if defined(__DJGPP__) // Protected Mode + +void plScnWrite(unsigned x, unsigned y, unsigned short* buf, unsigned nch) +{ + plScnInit(); + movedata(_my_ds(), (unsigned) buf, _dos_ds, plScnI.s_pbase+(((y * plScnI.s_wid) + x)*2), nch*2); +} + +void plScnRead(unsigned x, unsigned y, unsigned short* buf, unsigned nch) +{ + plScnInit(); + movedata(_dos_ds, plScnI.s_pbase+((y * plScnI.s_wid) + x)*2, _my_ds(), (unsigned) buf, nch*2); +} + +static void moveVm(unsigned to, unsigned from, unsigned len) +{ + movedata(_dos_ds, plScnI.s_pbase + from*2, _dos_ds, plScnI.s_pbase + to*2, len*2); +} + + +/****************************************************************************/ +/* */ +/* CODING: Dos4GW implementation.. */ +/* */ +/****************************************************************************/ +#elif defined(__DOS4G__) + +void plScnWrite(unsigned x, unsigned y, unsigned short* buf, unsigned nch) +{ + plScnInit(); + memcpy((UBYTE*) plScnI.s_pbase+(((y * plScnI.s_wid) + x)*2), buf, nch<<1); +} + +void plScnRead(unsigned x, unsigned y, unsigned short* buf, unsigned nch) +{ + plScnInit(); + memcpy(buf, (UBYTE*)plScnI.s_pbase+(((y * plScnI.s_wid) + x)*2), nch<<1); +} + +static void moveVm(unsigned to, unsigned from, unsigned len) +{ + memcpy((UBYTE*) plScnI.s_pbase+to*2, (UBYTE*) plScnI.s_pbase+from*2, len*2); +} + + +/****************************************************************************/ +/* */ +/* REAL MODE implementation. */ +/* */ +/****************************************************************************/ + +#elif defined(__MSDOS__) // REAL Mode +#include + +void plScnWrite(unsigned x, unsigned y, unsigned short* buf, unsigned nch) +{ + plScnInit(); + memcpy(MK_FP(plScnI.s_pseg, ((y * plScnI.s_wid) + x)*2), buf, nch<<1); +} + +void plScnRead(unsigned x, unsigned y, unsigned short* buf, unsigned nch) +{ + plScnInit(); + memcpy(buf, MK_FP(plScnI.s_pseg, ((y * plScnI.s_wid) + x)*2), nch<<1); +} + +static void moveVm(unsigned to, unsigned from, unsigned len) +{ + memcpy(MK_FP(plScnI.s_pseg, to*2), MK_FP(plScnI.s_pseg, from*2), len << 1); +} + +#endif + + +/****************************************************************************/ +/* */ +/* CODING: Screen - Shared Base functions. */ +/* */ +/****************************************************************************/ +/* + * plScnWidth() returns the width of the screen. + */ +int plScnWidth(void) +{ + plScnInit(); + return plScnI.s_wid; +} + + +/* + * plScnHeight() returns the current height of the screen. + */ +int plScnHeight(void) +{ + plScnInit(); + return plScnI.s_hig; +} + + +/* + * plScnType() returns the current screen type. + */ +enum ePlScnType plScnType(void) +{ + plScnInit(); + return plScnI.s_type; +} + + +/* + * plScnIsMono() returns T if the screen is a MONO screen. + */ +boolean plScnIsMono(void) +{ + plScnInit(); + return plScnI.s_ismono; +} + + +/****************************************************************************/ +/* */ +/* CODING: Screen - Set and Scroll functions. */ +/* */ +/****************************************************************************/ +#define BUFSZ 150 + +/* + * plScnSetCell() + */ +void plScnSetCell(unsigned x, unsigned y, unsigned wid, unsigned hig, UWORD cell) +{ + UWORD buf[BUFSZ], *p, *pend; + unsigned len, lleft, px; + + //** Fill buffer, + len = wid; + if(len > BUFSZ) len = BUFSZ; + p = buf; + pend= p + len; + while(p < pend) *p++ = cell; // Set as much as needed, + + //** For all lines, + while(hig-- > 0) + { + //** For the current line, + lleft = wid; + px = x; + while(lleft > 0) + { + len = lleft; // Determine #bytes from buf to use, + if(len > BUFSZ) len = BUFSZ; + plScnWrite(px, y, buf, len); + px += len; + lleft -= len; + } + y++; + } +} + + +/* + * plScnScrollUp() scrolls the region specified UP. + */ +void plScnScrollUp(int x, int y, int ex, int ey, int nlines, UWORD fill) +{ + int from, to; + + //** Calculate the from and to offsets; + to = y*plScnI.s_wid + x; // TO is top-of-window, + from= to + nlines*plScnI.s_wid; // FROM is #lines further down, + while(y < ey-nlines) + { + moveVm(to, from, (ex-x)); + to += plScnI.s_wid; + from+= plScnI.s_wid; + y++; + } + plScnSetCell(x, y, (ex-x), nlines, fill); // Clear bottom. +} + + +/* + * plScnScrollDown() scrolls the region DOWN. + */ +void plScnScrollDown(int x, int y, int ex, int ey, int nlines, UWORD fill) +{ + int from, to, len; + + //** Scrolling down: move from bottom to top; + to = ey * plScnI.s_wid + x; + from= to - plScnI.s_wid*nlines; + while(ey > y) + { + ey--; // Back one line; + from -= plScnI.s_wid; + to -= plScnI.s_wid; + moveVm(to, from, (ex-x)); + } + plScnSetCell(x, y, (ex-x), nlines, fill); +} + + +/****************************************************************************/ +/* */ +/* CODING: Keyboard interface for DOS and DOS extender(s).. */ +/* */ +/****************************************************************************/ +/* + * Memo to self: I've changed the "get character" request code from the 00h + * and 01h to 10h and 11h (extended keyboard). I should inquire the BIOS about + * the availability of these calls, but preliminary tests show that most + * BIOSes lie about the keyboard type, or do not implement the required + * int15 calls proper. + * Should work for most modern machines! + */ + +/* + * kbHasChar() returns T if a character is present in the keyboard buffer. It + * is checked by comparing the keyboard queue ptrs in the bios segment. + */ +static boolean kbHasChar(void) +{ + UWORD p1, p2; + union dosxReg r; + +#if 0 // Switched off for extended kbd support. + dosxMemRead(&p1, 0x0040001aul, 2); // Get 1st keybd pointer, + dosxMemRead(&p2, 0x0040001cul, 2); // And 2nd, + if(p1 == p2) return FALSE; // Exit if not ok; +#endif + + //** Now ask if a real code is available by non-destructive qry of bios. + memset(&r, 0, sizeof(r)); // Clear unused registers, + r.w.ax = 0x1100; // !! Was 0x0100 + dosxIntr(0x16, &r); // Call keyboard shit. + if(r.w.flags & 0x40) return FALSE; // Z flag SET -> no data + return TRUE; +} + + +/* + * kbDosRead() does a destructive read by calling BIOS call 16H code 0. + */ +static boolean kbDosRead(struct plKbdInfo* ki) +{ + union dosxReg r; + UBYTE v; + + memset(&r, 0, sizeof(r)); // Make sure all segregs are 0 + r.w.ax = 0x1000; // Was 0x0, now extended + dosxIntr(0x16, &r); + if((r.x.flags & 0x40) == 0) // Z flag NOT set? + { + ki->ki_scan = r.h.ah; + ki->ki_ascii= r.h.al; + dosxMemRead(&v, 0x00400017ul, 1); + + ki->ki_flags= (v & 0x03) ? PLKF_SHIFT : 0; + if(v & 0x08) ki->ki_flags |= PLKF_ALT; + if(v & 0x04) ki->ki_flags |= PLKF_CTRL; + if(v & 0x10) ki->ki_flags |= PLKF_SCROLLLOCK; + if(v & 0x20) ki->ki_flags |= PLKF_NUMLOCK; + if(v & 0x40) ki->ki_flags |= PLKF_CAPSLOCK; + + return TRUE; + } + return FALSE; +} + + +/* + * kbDosIdle() + */ +static void kbDosIdle(void) +{ + union dosxReg r; + + memset(&r, 0, sizeof(r)); + dosxIntr(0x28, &r); +} + + +/* + * plKbdReadF() does a non-waiting read of the keyboard. + */ +boolean plKbdReadF(struct plKbdInfo* ki) +{ + if(kbHasChar()) + { + if(kbDosRead(ki)) + return TRUE; + } + kbDosIdle(); + return FALSE; +} + + +/****************************************************************************/ +/* */ +/* CODING: Mouse - Dos MOUSE interface (Mou calls). */ +/* */ +/****************************************************************************/ +/*--------------------------------------------------------------------------*/ +/* DEFINES: Mouse command codes. */ +/*--------------------------------------------------------------------------*/ +#define MC_RESET 0x0000 +#define MC_CURSEN 0x0001 /* Enable cursor position */ +#define MC_CURSDI 0x0002 /* Disable cursor */ +#define MC_GETCUR 0x0003 /* Get cursor position */ +#define MC_SETCUR 0x0004 /* Set cursor position */ +#define MC_GETBPRESS 0x0005 /* Get button press state */ +#define MC_GETBRELEASE 0x0006 /* Button release state */ +#define MC_SETXRANGE 0x0007 /* Set X cursor range */ +#define MC_SETYRANGE 0x0008 /* Set Y cursor range */ +#define MC_GRCURSOR 0x0009 /* Set Graphic cursor style */ +#define MC_TXCURSOR 0x000a /* Set text mode cursor style */ +#define MC_GETMOTION 0x000b /* Get mouse motion # */ +#define MC_SETEVENT 0x000c /* DefiNE event handler location */ +#define MC_LPENABLE 0x000d /* Enable light pen emulation */ +#define MC_LPDISABLE 0x000e /* Disable light pen emulation */ +#define MC_SETSENS 0x000f /* Set sensitivity (mousemove/pixel) */ +#define MC_CDRANGE 0x0010 /* Disable cursor in given range */ +#define MC_DBLSPEEDTH 0x0013 /* DefiNE double-speed treshold */ + + +static ULONG MouseCursorState; /* Mouse saved cursor state */ +static boolean MousePresent; // T if mouse was located at init. +static ULONG MousePressCount; // #times the mouse was clicked. + +/* + * MOUSIsPresent() returns T if the mouse is present. It can be called only + * when the MOUSInit call has been done. + */ +boolean MOUSIsPresent(void) +{ + return MousePresent; +} + + +/* + * MOUSPressCount() + */ +ULONG MOUSPressCount(void) +{ + return MousePressCount; +} + + +/* + * MOUSInit() initializes the mouse driver. It returns FALSE if no mouse's + * present. When it's not called by the user program no mouse support + * is given.. + */ +boolean MOUSInit(void) +{ +// UBYTE *p; + union dosxReg r; + + if(! MousePresent) /* If not already called */ + { +#if 0 // No vector for EXTENDERS + /**** Get the contents of interrupt 33H ****/ + p = (UBYTE *)getvect(0x33); + if(p == NULL || *p == 0xcf) return FALSE; +#endif + + /**** Mouse driver present: Call the mouse driver ****/ + memset(&r, 0, sizeof(r)); + r.w.ax = MC_RESET; + dosxIntr(0x33, &r); + if(r.w.ax != 0) /* Mouse attached? */ + { + MousePresent = TRUE; + MOUSSetTextCursor(0, 0); /* Use default text cursor */ + } + MouseCursorState= 0; /* Cursor invisible */ + } + else + assert(0); + return MousePresent; /* Return mouse state */ +} + + +/* + * MOUSExit() doesn't do a thing but is called to maintain compatibility. + */ +void MOUSExit(void) +{ + MousePresent = FALSE; + MouseCursorState= 0; +} + + +/* + * MOUSCursen() enables/disables the mouse cursor. It takes notice of the + * previous state and calls the routine ONLY if the state needs a change. + */ +void MOUSCursen(boolean enable) +{ + union dosxReg r; + + if(MousePresent) + { + if( (enable && !(MouseCursorState & 1)) || + (!enable && (MouseCursorState & 1))) + { + memset(&r, 0, sizeof(r)); + r.w.ax = enable ? MC_CURSEN : MC_CURSDI; + dosxIntr(0x33, &r); + if(enable) + MouseCursorState |= 1; + else + MouseCursorState &= ~1; + } + } +} + + +/* + * MOUSSaveCurs() saves the current cursor state. + */ +void MOUSSaveCurs(void) +{ + ULONG state; + + state = MouseCursorState & 1; + MouseCursorState = (MouseCursorState << 1) | state; +} + + +/* + * MOUSRestCurs() restores the last cursor state. + */ +void MOUSRestCurs(void) +{ + ULONG nstate; + + nstate = MouseCursorState >> 1; // Get new state of cursor, + MOUSCursen((boolean) (nstate & 1) ); // Make mouse's new state, + MouseCursorState = nstate; // And set the new state. +} + + +/* + * MOUSPos() returns the current mouse position and the button states. + */ +void MOUSPos(UWORD *x, UWORD *y, boolean *leftbutton, boolean *rightbutton) +{ + union dosxReg r; + + if(MousePresent) + { + memset(&r, 0, sizeof(r)); + r.w.ax = MC_GETCUR; + dosxIntr(0x33, &r); + if(leftbutton != NULL) *leftbutton = (r.w.bx & 1) != 0; + if(rightbutton != NULL) *rightbutton = (r.w.bx & 2) != 0; + + if(x != NULL) *x = r.w.cx; + if(y != NULL) *y = r.w.dx; + } +} + + +/* + * MOUSSetpos() sets a new mouse cursor position + */ +void MOUSSetpos(UWORD x, UWORD y) +{ + union dosxReg r; + + if(MousePresent) + { + r.w.ax = MC_SETCUR; + r.w.cx = x; + r.w.dx = y; + dosxIntr(0x33, &r); + } +} + + +/* + * MOUSSetTextCursor() sets the text cursor style. It always selects a + * software cursor and, if both screenmask and cursormask are zero it + * selects an inverse 'o' (0x09) as cursor character. + */ +void MOUSSetTextCursor(UWORD screenmask, UWORD cursormask) +{ + union dosxReg r; + + if(MousePresent) + { + memset(&r, 0, sizeof(r)); + r.w.ax = MC_TXCURSOR; /* Define text cursor command */ + r.w.bx = 0; /* Software text cursor */ + if(screenmask == 0 && cursormask == 0) + { +#if 0 + r.w.cx = 0x0000; /* Screen mask value: all bits OFF */ + r.w.dx = 0x1f09; /* Cursor mask: an 'o' */ +#endif + r.w.cx = 0x7700; /* Screen mask value */ + r.w.dx = 0x77fe; /* Cursor: a blob */ + + } + else + { + r.w.cx = screenmask; + r.w.dx = cursormask; + } + dosxIntr(0x33, &r); + } +} + + +/* + * MOUSPressed() returns TRUE when the mouse key was pressed AND: + * a. The mouse key has been released since the last call OR + * b. The mouse position has changed. + * It returns the new mouse coordinates in character positions. + */ +boolean MOUSPressed(UWORD *x, UWORD *y) +{ + boolean leftbutton; + static boolean waspressed; + static UWORD lx, ly; + + if(MousePresent) + { + MOUSPos(x, y, &leftbutton, NULL); /* Get current mouse pos & state */ + *x /= 8; /* Scale to characters */ + *y /= 8; /* Idem */ + if(leftbutton) /* Key pressed? */ + { + /**** Key was pressed! Have the coords changed since the last ****/ + /**** time? ****/ + if(*x == lx && *y == ly && waspressed) return FALSE; /* Nothing changed */ + + lx = *x; + ly = *y; + waspressed= TRUE; + return TRUE; + } + else + waspressed = FALSE; + } + return FALSE; +} + + + +#endif // DOS || DOSP32 diff --git a/src/s_direct.cpp b/src/s_direct.cpp new file mode 100644 index 0000000..2da5d51 --- /dev/null +++ b/src/s_direct.cpp @@ -0,0 +1,435 @@ +/* s_direct.cpp + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +// TODO: on OS/2 choose between UNIX and OS/2 style patterns (now OS/2 only) +// TODO: on OS/2 fetch multiple entries at once and cache them for speed +#include "fte.h" + +#ifdef OS2 +#define INCL_BASE +#include +#endif + +#ifdef NT +#define WIN32_LEAN_AND_MEAN 1 +#include +#endif + +#if defined(DOSP32) || (defined(NT) && defined(USE_DIRENT)) // NT ? +# include "port.h" +#endif + + +#ifdef DJGPP +#include +static int my_stat(const char *name, struct stat *s) +{ + unsigned short f = _djstat_flags; + // speed up directory access by turning off unused stat functionality + _djstat_flags |= _STAT_INODE; + _djstat_flags |= _STAT_EXEC_EXT; + _djstat_flags |= _STAT_EXEC_MAGIC; + _djstat_flags |= _STAT_DIRSIZE; + //_djstat_flags |= _STAT_ROOT_TIME; + _djstat_flags &= ~_STAT_ROOT_TIME; + _djstat_flags |= _STAT_WRITEBIT; + int r = stat(name,s); + _djstat_flags = f; + return r; +} +#endif + + +FileInfo::FileInfo(char *Name, int Type, off_t Size, time_t MTime) { + name = new char[strlen (Name) + 1]; + if (name) + strcpy(name, Name); + size = Size; + type = Type; + mtime = MTime; +} + +FileInfo::~FileInfo() { + delete [] name; +} + +FileFind::FileFind(const char *aDirectory, const char *aPattern, int aFlags) { + Directory = new char[strlen(aDirectory) + 1]; + if (Directory) { + strcpy(Directory, aDirectory); + Slash(Directory, 0); + } + if (aPattern) { + Pattern = new char[strlen(aPattern) + 1]; + if (Pattern) + strcpy(Pattern, aPattern); + } else { + Pattern = 0; + } + Flags = aFlags; +#if defined(USE_DIRENT) + //#if defined(UNIX) || defined(DOSP32) || defined(NT) + dir = 0; +#elif defined(OS2) && !defined(USE_DIRENT) + dir = 0; +#elif defined(NT) && !defined(USE_DIRENT) + dir = 0; +#endif +} + +FileFind::~FileFind() { + delete [] Directory; + if (Pattern) + delete [] Pattern; + //#if defined(UNIX) || defined(DOSP32) || defined(NT) +#if defined(USE_DIRENT) + if (dir) + closedir(dir); +#elif defined(OS2) && !defined(USE_DIRENT) + if (dir) + DosFindClose(dir); +#elif defined(NT) && !defined(USE_DIRENT) + if (dir) + FindClose((HANDLE)dir); +#endif +} + +int FileFind::FindFirst(FileInfo **fi) { + //#if defined(UNIX) || defined(NT) || defined(DOSP32) +#if defined(USE_DIRENT) + if (dir) + closedir(dir); + if ((dir = opendir(Directory)) == 0) + return -1; + return FindNext(fi); +#elif defined(OS2) && !defined(USE_DIRENT) + char fullpattern[MAXPATH]; + HDIR hdir = HDIR_CREATE; + ULONG attr = FILE_ARCHIVED | FILE_READONLY; + ULONG count = 1; + FILEFINDBUF3 find; // need to improve to fetch multiple entries at once + char fullpath[MAXPATH]; + char *name; + struct tm t; + int rc; + + if (dir) + DosFindClose(dir); + + if (Flags & ffDIRECTORY) + attr |= FILE_DIRECTORY; + + if (Flags & ffHIDDEN) + attr |= FILE_HIDDEN | FILE_SYSTEM; // separate ? + + if (Pattern) + JoinDirFile(fullpattern, Directory, Pattern); + else + JoinDirFile(fullpattern, Directory, "*"); + + if ((rc = DosFindFirst(fullpattern, + &hdir, + attr, + &find, sizeof(find), + &count, + FIL_STANDARD)) != 0) + { + //fprintf(stderr, "%s: %d\n\n", fullpattern, rc); + return -1; + } + dir = hdir; + if (count != 1) + return -1; + name = find.achName; + if (Flags & ffFULLPATH) { + JoinDirFile(fullpath, Directory, name); + name = fullpath; + } + memset((void *)&t, 0, sizeof(t)); + t.tm_year = find.fdateLastWrite.year + 80; // ugh! + t.tm_mon = find.fdateLastWrite.month - 1; + t.tm_mday = find.fdateLastWrite.day; + t.tm_hour = find.ftimeLastWrite.hours; + t.tm_min = find.ftimeLastWrite.minutes; + t.tm_sec = find.ftimeLastWrite.twosecs * 2; // ugh! + t.tm_isdst = -1; + *fi = new FileInfo(name, + (find.attrFile & FILE_DIRECTORY) ? fiDIRECTORY : fiFILE, + find.cbFile, + mktime(&t)); + return 0; +#elif defined(NT) && !defined(USE_DIRENT) +#if defined(USE_VCFIND) + char fullpattern[MAXPATH]; + + _finddata_t find; // need to improve to fetch multiple entries at once + char fullpath[MAXPATH]; + char *name; + struct tm t; + int rc; + + if (dir) + _findclose(dir); + + /*if (Flags & ffDIRECTORY) + attr |= FILE_DIRECTORY; + + if (Flags & ffHIDDEN) + attr |= FILE_HIDDEN | FILE_SYSTEM; // separate ? + */ + if (Pattern) + JoinDirFile(fullpattern, Directory, Pattern); + else + JoinDirFile(fullpattern, Directory, "*"); + + if ((rc = _findfirst(fullpattern, &find)) == -1) + { + // fprintf(stderr, "%s: %d\n\n", fullpattern, rc); + return -1; + } + dir = rc; + + name = find.name; + if (Flags & ffFULLPATH) { + JoinDirFile(fullpath, Directory, name); + name = fullpath; + } + + *fi = new FileInfo(name, + (find.attrib & _A_SUBDIR) ? fiDIRECTORY : fiFILE, + find.size, + find.time_create); + return 0; +#else + char fullpattern[MAXPATH]; + + WIN32_FIND_DATA find; // need to improve to fetch multiple entries at once + char fullpath[MAXPATH]; + char *name; + struct tm t; + SYSTEMTIME st; + FILETIME localft; // needed for time conversion + int rc; + + if (dir) + _findclose(dir); + + /*if (Flags & ffDIRECTORY) + attr |= FILE_DIRECTORY; + + if (Flags & ffHIDDEN) + attr |= FILE_HIDDEN | FILE_SYSTEM; // separate ? + */ + if (Pattern) + JoinDirFile(fullpattern, Directory, Pattern); + else + JoinDirFile(fullpattern, Directory, "*"); + + if ((rc = (int) FindFirstFile(fullpattern, &find)) < 0) + { + //fprintf(stderr, "%s: %d\n\n", fullpattern, rc); + return -1; + } + dir = rc; + + name = find.cFileName; + if (Flags & ffFULLPATH) { + JoinDirFile(fullpath, Directory, name); + name = fullpath; + } + + /* + * since filetime is in UTC format we need to convert it first to + * localtime and when we have "correct" time we can use it. + */ + + FileTimeToLocalFileTime(&find.ftLastWriteTime, &localft); + FileTimeToSystemTime(&localft, &st); + + t.tm_year = st.wYear - 1900; + t.tm_mon = st.wMonth - 1; // in system time january is 1... + t.tm_mday = st.wDay; + t.tm_hour = st.wHour; + t.tm_min = st.wMinute; + t.tm_sec = st.wSecond; + t.tm_isdst = -1; + + + *fi = new FileInfo(name, + (find.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? fiDIRECTORY : fiFILE, + find.nFileSizeLow, // !!! + mktime(&t)); + return 0; +#endif +#endif +} + +int FileFind::FindNext(FileInfo **fi) { + //#if defined(UNIX) || defined(NT) || defined(DOSP32) +#if defined(USE_DIRENT) + struct dirent *dent; + char fullpath[MAXPATH]; + char *name; + + *fi = 0; +again: + if ((dent = readdir(dir)) == NULL) + return -1; + name = dent->d_name; + + if (name[0] == '.') + if (!(Flags & ffHIDDEN)) + goto again; + + if (Pattern && fnmatch(Pattern, dent->d_name, 0) != 0) + goto again; + + if (Flags & ffFULLPATH) { + JoinDirFile(fullpath, Directory, dent->d_name); + name = fullpath; + } + + if (Flags & ffFAST) { + *fi = new FileInfo(name, fiUNKNOWN, 0, 0); + } else { + struct stat st; + + if (!(Flags & ffFULLPATH)) // need it now + JoinDirFile(fullpath, Directory, dent->d_name); + + if ( +#if defined(DJGPP) + my_stat +#elif defined(UNIX) // must use lstat if available + lstat +#else + stat +#endif + (fullpath, &st) != 0 && 0) + goto again; + + if (!(Flags & ffDIRECTORY) && S_ISDIR(st.st_mode)) + goto again; + + *fi = new FileInfo(name, + S_ISDIR(st.st_mode) ? fiDIRECTORY : fiFILE, + st.st_size, + st.st_mtime); + } + //printf("ok\n"); + return 0; +#elif defined(OS2) && !defined(USE_DIRENT) + ULONG count = 1; + FILEFINDBUF3 find; // need to improve to fetch multiple entries at once + char fullpath[MAXPATH]; + char *name; + struct tm t; + int rc; + + if ((rc = DosFindNext(dir, + &find, sizeof(find), + &count)) != 0) + { + //fprintf(stderr, "%d\n\n", rc); + return -1; + } + if (count != 1) + return -1; + name = find.achName; + if (Flags & ffFULLPATH) { + JoinDirFile(fullpath, Directory, name); + name = fullpath; + } + memset((void *)&t, 0, sizeof(t)); + t.tm_year = find.fdateLastWrite.year + 80; + t.tm_mon = find.fdateLastWrite.month - 1; + t.tm_mday = find.fdateLastWrite.day; + t.tm_hour = find.ftimeLastWrite.hours; + t.tm_min = find.ftimeLastWrite.minutes; + t.tm_sec = find.ftimeLastWrite.twosecs * 2; // ugh! + t.tm_isdst = -1; + *fi = new FileInfo(name, + (find.attrFile & FILE_DIRECTORY) ? fiDIRECTORY : fiFILE, + find.cbFile, + mktime(&t)); + + return 0; +#elif defined(NT) && !defined(USE_DIRENT) +#if defined(USE_VCFIND) + _finddata_t find; + char fullpath[MAXPATH]; + char *name; + struct tm t; + int rc; + + if ((rc = _findnext(dir, + &find)) != 0) + { + // fprintf(stderr, "%d\n\n", rc); + return -1; + } + + name = find.name; + if (Flags & ffFULLPATH) { + JoinDirFile(fullpath, Directory, name); + name = fullpath; + } + + *fi = new FileInfo(name, + (find.attrib & _A_SUBDIR) ? fiDIRECTORY : fiFILE, + find.size, + find.time_create); + return 0; +#else + WIN32_FIND_DATA find; + char fullpath[MAXPATH]; + char *name; + struct tm t; + SYSTEMTIME st; + FILETIME localft; // needed for time conversion + int rc; + + if ((rc = FindNextFile((HANDLE)dir, + &find)) != TRUE) + { + //fprintf(stderr, "%d\n\n", rc); + return -1; + } + + name = find.cFileName; + if (Flags & ffFULLPATH) { + JoinDirFile(fullpath, Directory, name); + name = fullpath; + } + + /* + * since filetime is in UTC format we need to convert it first to + * localtime and when we have "correct" time we can use it. + */ + + FileTimeToLocalFileTime(&find.ftLastWriteTime, &localft); + FileTimeToSystemTime(&localft, &st); + + t.tm_year = st.wYear - 1900; + t.tm_mon = st.wMonth - 1; // in system time january is 1... + t.tm_mday = st.wDay; + t.tm_hour = st.wHour; + t.tm_min = st.wMinute; + t.tm_sec = st.wSecond; + t.tm_isdst = -1; + + *fi = new FileInfo(name, + (find.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? fiDIRECTORY : fiFILE, + find.nFileSizeLow, + mktime(&t)); + return 0; +#endif + // put code here +#endif +} diff --git a/src/s_direct.h b/src/s_direct.h new file mode 100644 index 0000000..d18a9ad --- /dev/null +++ b/src/s_direct.h @@ -0,0 +1,63 @@ +/* s_direct.h + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#ifndef __SDIRECT_H +#define __SDIRECT_H + +// error handling needs some work + +#define fiUNKNOWN 0 +#define fiFILE 1 +#define fiDIRECTORY 2 + +class FileInfo { +private: + char *name; // minimum set of file information + off_t size; + time_t mtime; + int type; + +public: + FileInfo(char *Name, int type, off_t Size, time_t MTime); + ~FileInfo(); + + char *Name() { return name; } + off_t Size() { return size; } + int Type() { return type; } + time_t MTime() { return mtime; } +}; + +#define ffFAST 1 // optimization for UNIX (return name only, NO TYPE CHECK), ignored on OS/2 and NT +#define ffFULLPATH 2 // return full path to files +#define ffDIRECTORY 4 // return directories beside files (see ffFAST) +#define ffHIDDEN 8 // return hidden files (dot-files for UNIX) + +class FileFind { +private: + char *Directory; + char *Pattern; + int Flags; + +#if defined(USE_DIRENT) + DIR *dir; +#elif defined(OS2) && !defined(USE_DIRENT) + unsigned long dir; // should be HDIR, but we don't #include huge os2.h globally +#elif defined(NT) && !defined(USE_DIRENT) + unsigned long dir; // should be HANDLE +#endif + +public: + FileFind(const char *aDirectory, const char *aPattern, int aFlags); + ~FileFind(); + + int FindFirst(FileInfo **fi); + int FindNext(FileInfo **fi); +}; + +#endif diff --git a/src/s_files.cpp b/src/s_files.cpp new file mode 100644 index 0000000..6a44579 --- /dev/null +++ b/src/s_files.cpp @@ -0,0 +1,469 @@ +/* s_files.cpp + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#include "sysdep.h" +#include "s_files.h" + +#if defined(OS2) +#define INCL_DOS +#include +#endif + +#if defined(NT) +# define WIN32_LEAN_AND_MEAN 1 +# include +#endif + +#if defined(DOSP32) +# include "port.h" +#endif + + +#if defined(DJGPP) +static inline int is_end(int c) +{ + return c == 0 || c == '.' || c == '/'; +} + +static inline int is_filename_char(int c) +{ + return (strchr("+<>",c) == NULL); +} + + +static void my_fixpath(const char *in, char *out) { + // this does most of the cleanup + _fixpath(in,out); + if (_USE_LFN) + return; + + // handle 8+3 restrictions + char tmp[MAXPATH]; + char *t = tmp; + char *o = out; + if (o[0] && o[1] == ':') { + *t++ = *o++; + *t++ = *o++; + } + while (*o) { + int i; + // copy over slash + if (*o == '/') + *t++ = *o++; + // copy over filename (up to 8 chars) + for (i = 0; i < 8 && !is_end(*o); o++) + if (is_filename_char(*o)) + *t++ = *o, i++; + // copy over extension (up to 3 chars) + if (*o == '.') { + // don't copy a trailing '.' unless following a ':' + if (o[1] == 0 && o > out && o[-1] != ':') + break; + *t++ = (i > 0 ? '.' : '_'); + o++; + for (i = 0; i < 3 && !is_end(*o); o++) + if (is_filename_char(*o)) + *t++ = *o, i++; + } + // find next slash + while (*o && *o != '/') + o++; + } + *t++ = 0; +#if 0 + if (strcmp(out,tmp) != 0) + fprintf(stderr,"fix: '%s'->'%s'\n",out,tmp); +#endif + strcpy(out,tmp); +} +#endif + + +char *Slash(char *Path, int Add) { + int len = strlen(Path); + + if (Add) { + if ((len == 0) || !ISSLASH(Path[len - 1])) { + Path[len] = SLASH; + Path[len+1] = 0; + } + } else { + if ((len > 1) +#if PATHTYPE == PT_DOSISH + && ((len > 3) || (Path[1] != ':')) +#endif + ) { + if (ISSLASH(Path[len - 1])) { + Path[len - 1] = 0; + } + } + } + return Path; +} + +char *SlashDir(char *Path) { + int len = strlen(Path); + if (len > 1) { +#if PATHTYPE == PT_DOSISH + if ((len == 2) && Path[1] == ':') { +#ifdef DJGPP + char tmp[MAXPATH]; + strcpy(tmp,Path); + my_fixpath(tmp,Path); + strcat(Path,SSLASH); +#else + Path[2] = SLASH; + Path[3] = 0; +#endif + } + else +#endif + if (!ISSLASH(Path[len - 1])) { + struct stat statbuf; + if (stat(Path, &statbuf) == 0) { + if (S_ISDIR(statbuf.st_mode)) { + Path[len] = SLASH; + Path[len+1] = 0; + } + } + } + } + return Path; +} + +int IsDirectory(const char *Path) { + int len = strlen(Path); + if (len > 0) { +#if PATHTYPE == PT_DOSISH + if ((len == 2) && Path[1] == ':') + return 1; + else +#endif + if (!ISSLASH(Path[len - 1])) { + struct stat statbuf; + if (stat(Path, &statbuf) == 0) { + if (S_ISDIR(statbuf.st_mode)) { + return 1; + } + } + return 0; + } else + return 1; + } + return 0; +} + +#if PATHTYPE == PT_DOSISH +static int GetDiskCurDir(int drive, char *dir) { + if (drive < 1 || drive > 26) + return -1; + +#if defined(__EMX__) + return (_getcwd1(dir, (char)(drive + 'A' - 1)) == 0) ? 0 : -1; +#elif defined(OS2) + { + ULONG len = MAXPATH - 4; // 'c:\0' + + return (DosQueryCurrentDir(drive, dir, &len) == 0) ? 0 : -1; + } +#elif defined(NT) + { + char orig[MAXPATH], newdrive[MAXPATH]; + + // set to new drive, get directory and restore original directory + if (!GetCurrentDirectory(sizeof(orig), orig)) + return -1; + newdrive[0] = drive + 'A' - 1; + newdrive[1] = ':'; + newdrive[2] = 0; + if (!SetCurrentDirectory(newdrive)) + return -1; + if (!GetCurrentDirectory(sizeof(newdrive), newdrive)) + return -1; + strcpy(dir, newdrive + 3); + + SetCurrentDirectory(orig); // ? check + return 0; + } +#elif defined(DOS) || defined(DOSP32) + return (plGetcurdir(drive, dir) != 0); +#endif +} + +static int SetDrive(int drive) { // 1 = A, 2 = B, 3 = C, ... + if (drive < 1 || drive > 26) + return -1; + + // mess + // _chdrive seems to be most portable between dosish systems, + // but seem to take different arguments ??? + +#if defined(__EMX__) + return _chdrive(drive + 'A' - 1); +#elif defined(OS2) + return (DosSetDefaultDisk(drive) == 0) ? 0 : -1; +#elif defined(NT) + char buf[3]; + + buf[0] = (char)(drive + 'A' - 1); + buf[1] = ':'; + buf[2] = '\0'; + return SetCurrentDirectory(buf) ? 0 : -1; +#elif defined(DOS) || defined(DOSP32) + unsigned int ndr; + + _dos_setdrive(drive, &ndr); + return 0; //(ndr == drive) ? 0 : -1; // ? +#endif +} +#endif + +#if PATHTYPE == PT_UNIXISH +int RemoveDots(char *Source, char *Dest) { + char *p; + char *d; + + p = Source; + d = Dest; + while (*p) { + // if ((strncmp(p, SSLASH SSLASH, 2) == 0)) { + if (ISSLASH(p[0]) && ISSLASH(p[1])) { + p++; + // } else if ((strncmp(p, SSLASH ".." SSLASH, 4) == 0) || (strcmp(p, SSLASH "..") == 0)) { + } else if (ISSLASH(p[0]) && p[1] == '.' && p[2] == '.' && + (ISSLASH(p[3]) || p[3] == 0)) { + p += 3; + while ((d > Dest) && !ISSEP(*d)) d--; + *d = 0; + continue; + // } else if ((strncmp(p, SSLASH "." SSLASH, 3) == 0) || (strcmp(p, SSLASH ".") == 0)) { + } else if (ISSLASH(p[0]) && p[1] == '.' && + (ISSLASH(p[2]) || p[2] == 0)) { + p += 2; + continue; + } + *d++ = *p++; + *d = 0; + } + *d = 0; + return 0; +} +#endif + +int ExpandPath(const char *Path, char *Expand) { + char Name[MAXPATH]; + + if (Path[0] == 0) { + Expand[0] = 0; + return 0; + } +#if PATHTYPE == PT_DOSISH + int slashed = 0; + + strcpy(Name, Path); + if (Name[0] != 0) + slashed = ISSLASH(Name[strlen(Name)-1]); + Slash(Name, 0); +#if defined(DJGPP) + my_fixpath(Name, Expand); +#else + //puts(Name); + if (Name[0] && Name[1] == ':' && Name[2] == 0) { // '?:' + int drive = Name[0]; + + strcpy(Expand, Name); + Expand[2] = '\\'; + Expand[3] = 0; + + drive = (int)(toupper(Name[0]) - 'A' + 1); + + if (GetDiskCurDir(drive, Expand + 3) == -1) + return -1; + } else { +#if defined(__EMX__) + if (_fullpath(Expand, Name, MAXPATH) == -1) return -1; +#else + if (_fullpath(Expand, Name, MAXPATH) == NULL) return -1; +#endif + } +#endif +#if defined(__EMX__) + { + char *p = Expand; + + if (p && *p) do { + if (ISSLASH(*p)) + *p = SLASH; + } while (*p++); + } +#endif + if (slashed) + SlashDir(Expand); + //puts(Expand); + return 0; +#endif +#if PATHTYPE == PT_UNIXISH + char Name2[MAXPATH]; + char *path, *p; + + strcpy(Name, Path); + switch (Name[0]) { + case SLASH: + break; + case '~': + if (Name[1] == SLASH || Name[1] == 0) { + path = Name + 1; + strncpy(Name2, getenv("HOME"), sizeof(Name2) - 1); + Name2[sizeof(Name2) - 1] = 0; + } else { + struct passwd *pwd; + + p = Name; + p++; + while (*p && (*p != SLASH)) p++; + if (*p == SLASH) { + path = p + 1; + *p = 0; + } else { + path = p; + } + pwd = getpwnam(Name + 1); + if (pwd == NULL) + return -1; + strcpy(Name2, pwd->pw_dir); + } + if (path[0] != SLASH) + Slash(Name2, 1); + strcat(Name2, path); + strcpy(Name, Name2); + break; + default: + if (getcwd(Name, MAXPATH) == NULL) return -1; + Slash(Name, 1); + strcat(Name, Path); + break; + } + return RemoveDots(Name, Expand); +#endif +} + +int IsSameFile(const char *Path1, const char *Path2) { + char p1[MAXPATH], p2[MAXPATH]; + + if (ExpandPath(Path1, p1) == -1) return -1; + if (ExpandPath(Path2, p2) == -1) return -1; + if (filecmp(p1, p2) == 0) return 1; + return 0; +} + +int JustDirectory(const char *Path, char *Dir) { + char *p; + + if (ExpandPath(Path, Dir) == -1) + strcpy(Dir, Path); + p = SepRChr(Dir); + if (p) { p[1] = 0; } + else Dir[0] = 0; + return 0; +} + +int JustLastDirectory(const char *Path, char *Dir) { + int lastSlash = strlen(Path); + while (lastSlash > 0 && !ISSEP(Path[lastSlash])) lastSlash--; + + int secondLastSlash = lastSlash; + while (secondLastSlash > 0 && !ISSEP(Path[secondLastSlash - 1])) secondLastSlash--; + + strncpy(Dir, Path + secondLastSlash, lastSlash - secondLastSlash); + Dir[lastSlash - secondLastSlash] = 0; + + return 0; +} + +int JustFileName(const char *Path, char *Name) { + int len = strlen(Path); + + while (len > 0 && !ISSEP(Path[len - 1])) len--; + strcpy(Name, Path + len); + return 0; +} + +int JustRoot(const char *Path, char *Root) { +#if PATHTYPE == PT_UNIXISH + strcpy(Root, SSLASH); +#else + strncpy(Root, Path, 3); + Root[3] = 0; +#endif + return 0; +} + +int FileExists(const char *Path) { + return (access(Path, 0) == 0) ? 1 : 0; +} + +int IsFullPath(const char *Path) { + if (ISSLASH(Path[0]) +#if PATHTYPE == PT_DOSISH + || (Path[0] != 0 && Path[1] == ':') +#endif + ) + return 1; + else + return 0; +} + +const char *ShortFName(const char *Path, int len) { + static char P[MAXPATH]; + char p1[MAXPATH]; + int l1; + + if (len < 10) len = 10; + if (ExpandPath(Path, p1) == -1) return Path; + l1 = strlen(p1); + if (l1 < len) { + strcpy(P, p1); + } else { + strncpy(P, p1, 3); + strcpy(P + 3, "..."); + strncpy(P + 6, p1 + l1 - len, len - 6); + } + return P; +} + + +int ChangeDir(char *Dir) { + Slash(Dir, 0); // remove last \ except in case of ?: +#if PATHTYPE == PT_DOSISH + if (Dir[0] && Dir[1] == ':') + if (SetDrive(toupper(Dir[0]) - 'A' + 1) == -1) + return -1; +#endif + if (chdir(Dir) == -1) + return -1; + return 0; +} + +int JoinDirFile(char *Dest, const char *Dir, const char *Name) { + strcpy(Dest, Dir); + Slash(Dest, 1); + strcat(Dest, Name); + return 0; +} + +char *SepRChr(char *Dir) +{ + char *p; + if (Dir && Dir[0]) { + for (p = Dir + strlen(Dir); p > Dir; p--) + if (ISSEP(p[-1])) + return p-1; + } + return NULL; +} diff --git a/src/s_files.h b/src/s_files.h new file mode 100644 index 0000000..79e7904 --- /dev/null +++ b/src/s_files.h @@ -0,0 +1,53 @@ +/* s_files.h + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#ifndef __FILESYS_H__ +#define __FILESYS_H__ + +#define SDOT "." + +#ifdef UNIX +#define SLASH '/' +#define SSLASH "/" + +#define ISSLASH(c) ((c) == SLASH) +#define ISSEP(c) ((c) == SLASH) +#endif + +#if defined(OS2) || defined(NT) || defined(DOS) || defined(DOSP32) +#if defined(DJGPP) +#define SLASH '/' +#define SSLASH "/" +#else +#define SLASH '\\' +#define SSLASH "\\" +#endif + +#define ISSLASH(c) (((c) == '/') || ((c) == '\\')) +#define ISSEP(c) (((c) == ':') || ISSLASH(c)) +#endif + +char *Slash(char *Path, int Add); +char *SlashDir(char *Path); +int ExpandPath(const char *Path, char *Expanded); +int CompletePath(const char *Path, char *Completed, int Num); +int IsSameFile(const char *Path1, const char *Path2); +int JustDirectory(const char *Path, char *Dir); +int JustFileName(const char *Path, char *Name); +int JustLastDirectory(const char *Path, char *Dir); +int JustRoot(const char *Path, char *Root); +int FileExists(const char *Path); +int IsFullPath(const char *Path); +int IsDirectory(const char *Path); +const char *ShortFName(const char *Path, int len); +int ChangeDir(char *Dir); +int JoinDirFile(char *Dest, const char *Dir, const char *Name); +char *SepRChr(char *Dir); + +#endif diff --git a/src/s_util.cpp b/src/s_util.cpp new file mode 100644 index 0000000..c8088ae --- /dev/null +++ b/src/s_util.cpp @@ -0,0 +1,239 @@ + +/* s_util.cpp + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#include "fte.h" + +#define BUF_SZ (sizeof(FileBuffer)) + +extern RxNode *CompletionFilter; + +// should use DosCopy under OS/2... +int copyfile(char *f1, char *f2) { // from F1 to F2 + void *buffer; + int fd1, fd2; + int rd; + + buffer = FileBuffer; + + if ((fd1 = open(f1, O_RDONLY | O_BINARY)) == -1) + return -1; + if ((fd2 = open(f2, O_WRONLY | O_BINARY | O_CREAT | O_TRUNC, 0666)) == -1) { + close(fd1); + return -1; + } + while ((rd = read(fd1, buffer, BUF_SZ)) > 0) { + if (write(fd2, buffer, rd) != rd) { + close(fd1); + close(fd2); + unlink(f2); + return -1; + } + } + close(fd2); + close(fd1); + return 0; +} + +char *MakeBackup(char *FileName, char *NewName) { +// static char NewName[260]; + int l = strlen(FileName); + if (l <= 0) + return NULL; + + /* try 1 */ + strcpy(NewName, FileName); + strcat(NewName, "~"); + if (!IsSameFile(FileName,NewName)) { + if (access(NewName, 0) == 0) // Backup already exists? + unlink(NewName); // Then delete the file.. + if (access(FileName, 0) != 0) // Original found? + return NewName; + if (copyfile(FileName, NewName) == 0) + return NewName; +#if 0 + if (errno == 2) + return NewName; /* file not found */ +#endif + } + + /* try 2: 8.3 */ + strcpy(NewName, FileName); + NewName[l-1] = '~'; + if (!IsSameFile(FileName,NewName)) { + if (access(NewName, 0) == 0) // Backup exists? + unlink(NewName); // Then delete; + if (access(FileName, 0) != 0) // Original exists? + return NewName; // If not-> return base.. + if (copyfile(FileName, NewName) == 0) + return NewName; +#if 0 + if (errno == 2) + return NewName; +#endif + } + + return NULL; +} + +int GetCharFromEvent(TEvent &E, char *Ch) { + *Ch = 0; + if (E.Key.Code & kfModifier) + return 0; + if (kbCode(E.Key.Code) == kbEsc) { *Ch = 27; return 1; } + if (kbCode(E.Key.Code) == kbEnter) { *Ch = 13; return 1; } + if (kbCode(E.Key.Code) == (kbEnter | kfCtrl)) { *Ch = 10; return 1; } + if (kbCode(E.Key.Code) == kbBackSp) { *Ch = 8; return 1; } + if (kbCode(E.Key.Code) == (kbBackSp | kfCtrl)) { *Ch = 127; return 1; } + if (kbCode(E.Key.Code) == kbTab) { *Ch = 9; return 1; } + if (kbCode(E.Key.Code) == kbDel) { *Ch = 127; return 1; } + if (keyType(E.Key.Code) == kfCtrl) { + *Ch = (char) (E.Key.Code & 0x1F); + return 1; + } + if (isAscii(E.Key.Code)) { + *Ch = (char)E.Key.Code; + return 1; + } + return 0; +} + +int CompletePath(const char *Base, char *Match, int Count) { + char Name[MAXPATH]; + const char *dirp; + char *namep; + int len, count = 0; + char cname[MAXPATH]; + int hascname = 0; + RxMatchRes RM; + FileFind *ff; + FileInfo *fi; + int rc; + + if (strcmp(Base, "") == 0) { + if (ExpandPath(".", Name) != 0) return -1; + } else { + if (ExpandPath(Base, Name) != 0) return -1; + } +// SlashDir(Name); + dirp = Name; + namep = SepRChr(Name); + if (namep == Name) { + dirp = SSLASH; + namep = Name + 1; + } else if (namep == NULL) { + namep = Name; + dirp = SDOT; + } else { + *namep = 0; + namep++; + } + + len = strlen(namep); + strcpy(Match, dirp); + SlashDir(Match); + cname[0] = 0; + + ff = new FileFind(dirp, "*", + ffDIRECTORY | ffHIDDEN +#if defined(USE_DIRENT) + | ffFAST // for SPEED +#endif + ); + if (ff == 0) + return 0; + rc = ff->FindFirst(&fi); + while (rc == 0) { + char *dname = fi->Name(); + + // filter out unwanted files + if ((strcmp(dname, ".") != 0) && + (strcmp(dname, "..") != 0) && + (!CompletionFilter || RxExec(CompletionFilter, dname, strlen(dname), dname, &RM) != 1)) + { + if (( +#if defined(UNIX) + strncmp +#else // os2, nt, ... + strnicmp +#endif + (namep, dname, len) == 0) + && (dname[0] != '.' || namep[0] == '.')) + { + count++; + if (Count == count) { + Slash(Match, 1); + strcat(Match, dname); + if ( +#if defined(USE_DIRENT) // for SPEED + IsDirectory(Match) +#else + fi->Type() == fiDIRECTORY +#endif + ) + Slash(Match, 1); + } else if (Count == -1) { + + if (!hascname) { + strcpy(cname, dname); + hascname = 1; + } else { + int o = 0; +#ifdef UNIX + while (cname[o] && dname[o] && (cname[o] == dname[o])) o++; +#endif +#if defined(OS2) || defined(NT) || defined(DOS) || defined(DOSP32) + while (cname[o] && dname[o] && (toupper(cname[o]) == toupper(dname[o]))) o++; +#endif + cname[o] = 0; + } + } + } + } + delete fi; + rc = ff->FindNext(&fi); + } + delete ff; + if (Count == -1) { + Slash(Match, 1); + strcat(Match, cname); + if (count == 1) SlashDir(Match); + } + return count; +} + +int UnTabStr(char *dest, int maxlen, const char *source, int slen) { + char *p = dest; + int i; + int pos = 0; + + maxlen--; + for (i = 0; i < slen; i++) { + if (maxlen > 0) { + if (source[i] == '\t') { + do { + if (maxlen > 0) { + *p++ = ' '; + maxlen--; + } + pos++; + } while (pos & 0x7); + } else { + *p++ = source[i]; + pos++; + maxlen--; + } + } else + break; + } + + //dest[pos] = 0; + *p = '\0'; + return pos; +} diff --git a/src/s_util.h b/src/s_util.h new file mode 100644 index 0000000..7887d75 --- /dev/null +++ b/src/s_util.h @@ -0,0 +1,34 @@ +/* s_util.h + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#ifndef __EDITOR_H__ +#define __EDITOR_H__ + +#define USE_CtrlEnter 1 + +#define S_BUSY 0 +#define S_INFO 1 +#define S_BOLD 2 +#define S_ERROR 3 + +char* MakeBackup(char *FileName, char *NewName); + +int GetPMClip(); +int PutPMClip(); + +int FileLoad(int createFlags, const char *FileName, const char *Mode, EView *View); +int MultiFileLoad(int createFlags, const char *FileName, const char *Mode, EView *View); +int ParseSearchOption(int replace, char c, unsigned long &opt); +int ParseSearchOptions(int replace, const char *str, unsigned long &Options); +int ParseSearchReplace(EBuffer *B, const char *str, int replace, SearchReplaceOptions &opt); +int SetDefaultDirectory(EModel *M); +int GetDefaultDirectory(EModel *M, char *Path, int MaxLen); +int UnTabStr(char *dest, int maxlen, const char *source, int slen); + +#endif diff --git a/src/simple.fte b/src/simple.fte new file mode 100644 index 0000000..fcd3e6a --- /dev/null +++ b/src/simple.fte @@ -0,0 +1,492 @@ +mode PLAIN +{ + ExpandTabs = 1; # expand tabs on display + BackSpKillTab = 1; # backspace kills entire tabs + DeleteKillTab = 1; # delete kills entire tabs + BackSpUnindents = 0; # backspace at bol unindents + SpaceTabs = 0; # insert tabs as spaces + CursorThroughTabs = 0; + PersistentBlocks = 0; # 1 = persistent blocks, 0 = transient + BackSpKillBlock = 1; # to delete block if marked + DeleteKillBlock = 1; # "" + InsertKillBlock = 1; # inserting char kills selected block +} + +object GLOBAL +{ + KeepHistory = 0; # load/save history on entry/exit + LoadDesktopOnEntry = 0; # load desktop on fte start + SaveDesktopOnExit = 0; # save desktop in ExitEditor + +%if(OS_UNIX) +%define(GUI_X11) +%endif + +%if(GUI_X11) +# X11 +# Any fixed-width font should do. Make sure it has all 256 characters +# defined or weird things can happen. + +# WindowFont = "fixed"; +# WindowFont = "6x8"; +# WindowFont = "7x13"; +# WindowFont = "8x13"; + WindowFont = "9x15"; +# WindowFont = "10x20"; +%endif + +} + +menu File { + item "&Open...\tF3" { FileOpen } + item "&Reload\tShift+F3" { FileReload } + item "&Save\tF2" { FileSave } + item "Save &As...\tShift+F2" { FileSaveAs } + item "Save Al&l\tCtrl+F2" { FileSaveAll } + item "&Close\tAlt+Q" { FileClose } + item; + item "&Next\tAlt+Left" { FileNext } + item "&Previous\tAlt+Right" { FilePrev } + item; + item "E&xit\tAlt+X" { ExitEditor } +} + +menu Edit { + item "&Undo\tAlt+BackSp" { Undo } + item "&Redo\tAlt+Shift+BackSp" { Redo } + item; + item "Cu&t\tShift+Del" { BlockCut } + item "&Copy\tCtrl+Ins" { BlockCopy } + item "&Paste\tShift+Ins" { BlockPasteStream } + item "&Unmark\tEsc" { BlockUnmark } + item; + item "&Delete line\tCtrl+Y" { KillLine } +} + +menu Search { + item "&Find...\tCtrl+F" { Find } + item "Find and &replace...\tCtrl+R" { FindReplace } + item "Repeat &Last find\tCtrl+L" { FindRepeat } + item; + item "&Goto line...\tAlt+J" { MoveToLine } +} + +menu Window { + item "Split &Horizontal\tShift+F2" { WinHSplit } + item "&Close view\tCtrl+Alt+F4" { WinClose } + item "Close &other views\tF5" { WinZoom } + item; + item "&Buffers\tAlt+0" { ViewBuffers } + item "&Directory\tC+M" { DirOpen } +} + +menu Options { + item "&Insert mode\tC+O C+I" { ToggleInsert } + item "&Word wrap\tC+O C+W" { ToggleWordWrap } +} + +menu Help { + item "&About..." { ShowVersion } +} + +menu Main { + submenu "&File", File; + submenu "&Edit", Edit; + submenu "&Search", Search; + submenu "&Window", Window; + submenu "&Options", Options; + submenu "&Help", Help; +} + +menu Local { + item "Cu&t\tShift+Del" { BlockCut } + item "&Copy\tCtrl+Ins" { BlockCopy } + item "&Paste\tShift+Ins" { BlockPasteStream } + item "&Unmark\tEsc" { BlockUnmark } + item; + item "Delete &line\tCtrl+Y" { KillLine } + item; + item "&Save\tF2" { FileSave } + item "Cl&ose\tAlt+Q" { FileClose } +} + +eventmap MODEL { # basic commands, for files, directories, message view, etc. + key [C+F2] { FileSaveAll } + key [F3] { FileOpen } + key [F4] { WinNext } + key [C+F4] { WinHSplit } + key [S+F4] { WinPrev } + key [A+S-F4] { WinClose } + key [F5] { WinZoom } + key [F6] { FileNext } + key [S+F6] { FilePrev } + key [A+S-F6] { FileLast } + key [F10] { MainMenu } + key [C+F9] { RunProgram } + key [S+F10] { LocalMenu } + + key [A+G-Up] { WinPrev } + key [A+G-Down] { WinNext } + key [A+G-Left] { FilePrev } + key [A+G-Right] { FileNext } + + key [A+G-PgUp] { WinPrev; MovePageUp; WinNext } + key [A+G-PgDn] { WinNext; MovePageDown; WinPrev } + key [A+C+G-PgUp] { WinNext; MovePageUp; WinPrev } + key [A+C+G-PgDn] { WinPrev; MovePageDown; WinNext } + + key [A+Q] { FileClose } + key [A+X] { ExitEditor } + + key [C+S+G-Up] { WinResize -1 } + key [C+S+G-Down] { WinResize +1 } + + # this is also useful for 'grep -n' etc. if configured + key [F9] { Compile; ViewMessages } + key [F11] { CompilePrevError } + key [F12] { CompileNextError } + key [S+F9] { ViewMessages } + + key [A+0] { ViewBuffers } + key [A+1] { SwitchTo 1 } + key [A+2] { SwitchTo 2 } + key [A+3] { SwitchTo 3 } + key [A+4] { SwitchTo 4 } + key [A+5] { SwitchTo 5 } + key [A+6] { SwitchTo 6 } + key [A+7] { SwitchTo 7 } + key [A+8] { SwitchTo 8 } + key [A+9] { SwitchTo 9 } +} + +eventmap PLAIN: MODEL { +# keymap for plaintext mode + MainMenu = 'Main'; # menu for menubar + LocalMenu = 'Local'; # local menu + + key [Esc] { BlockMarkStream; BlockUnmark } + key [F2] { FileSave } + key [S+F2] { FileSaveAs } + key [A+S-F2] { FileSave; FileClose } + key [S+F3] { FileReload; WinRefresh } + key [C+F3] { FileOpenInMode } + key [F7] { BlockBegin } + key [S+F7] { MoveBlockStart } + key [F8] { BlockEnd } + key [S+F8] { MoveBlockEnd } + key [G-Left] { MoveLeft } + key [C+G-Left] { MoveWordPrev } + key [G-Right] { MoveRight } + key [C+G-Right] { MoveWordNext } + key [G-Up] { MoveUp } + key [G-Down] { MoveDown } + key [G-Home] { MoveLineStart } + key [C+G-Home] { MovePageStart } + key [G-End] { MoveLineEnd } + key [C+G-End] { MovePageEnd } + key [G-PgUp] { MovePageUp } + key [C+G-PgUp] { MoveFileStart } + key [G-PgDn] { MovePageDown } + key [C+G-PgDn] { MoveFileEnd } +# key [A+G-Up] { ScrollUp } +# key [A+G-Down] { ScrollDown } +# key [A+G-Left] { ScrollLeft } +# key [A+G-Right] { ScrollRight } + + key [S+G-Left] { BlockExtendBegin; MoveLeft; BlockExtendEnd } + key [S+G-Right] { BlockExtendBegin; MoveRight; BlockExtendEnd } + +# key [G+0] { ToggleInsert } +# key [G+S+0] { InsertString 'foo' } + + key [C+G-S+Left] { BlockExtendBegin; MoveWordPrev; BlockExtendEnd } + key [C+G-S+Right] { BlockExtendBegin; MoveWordNext; BlockExtendEnd } + key [G-S+Up] { BlockExtendBegin; MoveUp; BlockExtendEnd } + key [G-S+Down] { BlockExtendBegin; MoveDown; BlockExtendEnd } + key [G-S+Home] { BlockExtendBegin; MoveLineStart; BlockExtendEnd } + key [G-S+End] { BlockExtendBegin; MoveLineEnd; BlockExtendEnd } + key [C+G-S+Home] { BlockExtendBegin; MovePageStart; BlockExtendEnd } + key [C+G-S+End] { BlockExtendBegin; MovePageEnd; BlockExtendEnd } + key [G-S+PgUp] { BlockExtendBegin; MovePageUp; BlockExtendEnd } + key [G-S+PgDn] { BlockExtendBegin; MovePageDown; BlockExtendEnd } + key [C+G-S+PgUp] { BlockExtendBegin; MoveFileStart; BlockExtendEnd } + key [C+G-S+PgDn] { BlockExtendBegin; MoveFileEnd; BlockExtendEnd } + key [A+G-S+Up] { BlockExtendBegin; ScrollUp; BlockExtendEnd } + key [A+G-S+Down] { BlockExtendBegin; ScrollDown; BlockExtendEnd } + key [A+G-S+Left] { BlockExtendBegin; ScrollLeft; BlockExtendEnd } + key [A+G-S+Right] { BlockExtendBegin; ScrollRight; BlockExtendEnd } + key [A+G-C+Up] { MovePrevEqualIndent } + key [A+G-C+Down] { MoveNextEqualIndent } + key [A+G-C+Left] { MovePrevTab } + key [A+G-C+Right] { MoveNextTab } + key [C+G-Ins] { BlockCopy } + key [C+G-Del] { BlockKill } + key [S+G-Ins] { BlockPasteStream } + key [S+G-Del] { BlockCut } + key [A+G-Ins] { BlockPasteColumn } + key [A+G-S+Ins] { BlockPasteLine } + key [G-Enter] { LineNew } + key [BackSp] { BackSpace } + key [G-Ins] { ToggleInsert } + key [G-Del] { Delete } + key [Tab] { InsertTab } + key [S+Tab] { InsertSpacesToTab 10 } + key [C+Tab] { CompleteWord } +# key [C+Tab] { InsertTab } + key [C+BackSp] { KillWordPrev } + key [C+S+BackSp] { KillToLineStart } + key [C+G-Enter] { LineSplit } + key [G-S+Enter] { LineInsert } + key [A+G-Enter] { LineAdd } + key [A+G-Del] { KillWord } + key [A+G-End] { KillToLineEnd } + key [A+BackSp] { Undo } + key [A+S+BackSp] { Redo } + + key [C+A_1] { GotoBookmark "1" } + key [C+A_2] { GotoBookmark "2" } + key [C+A_3] { GotoBookmark "3" } + key [C+A_4] { GotoBookmark "4" } + key [C+A_5] { GotoBookmark "5" } + key [C+A_6] { GotoBookmark "6" } + key [C+A_7] { GotoBookmark "7" } + key [C+A_8] { GotoBookmark "8" } + key [C+A_9] { GotoBookmark "9" } + key [C+A_0] { GotoBookmark "0" } + + key [C+P_1] { PlaceBookmark "1" } + key [C+P_2] { PlaceBookmark "2" } + key [C+P_3] { PlaceBookmark "3" } + key [C+P_4] { PlaceBookmark "4" } + key [C+P_5] { PlaceBookmark "5" } + key [C+P_6] { PlaceBookmark "6" } + key [C+P_7] { PlaceBookmark "7" } + key [C+P_8] { PlaceBookmark "8" } + key [C+P_9] { PlaceBookmark "9" } + key [C+P_0] { PlaceBookmark "0" } + + key [C+B] { FindRepeatReverse } + key [C+C] { MoveToColumn } + key [C+D] { LineDuplicate } + key [C+F] { Find } + key [C+I] { ListRoutines } + key [C+J] { LineJoin } +# key [C+L] { FindRepeat } + key [C+G] { FindRepeat } + key [C+M] { DirOpen } + key [C+N] { FindRepeatOnce } + key [C+Q] { InsertChar } + key [C+R] { FindReplace } + key [C+T] { KillWord } + key [C+Y] { KillLine } + key [C+E] { LineTrim } + key [A+A] { BlockMarkStream } + key [A+B] { MainMenu 'B' } + key [A+C] { BlockCopy } + key [A+D] { MainMenu 'D' } + key [A+E] { MainMenu 'E' } + key [A+F] { MainMenu 'F' } + key [A+G] { BlockCut } + key [A+H] { MainMenu 'H' } + key [A+I] { BlockIndent } + key [A+J] { MoveToLine } + key [A+K] { BlockMarkColumn } + key [A+L] { BlockMarkLine } + key [A+O] { MainMenu 'O' } + key [A+R] { WrapPara } # Reformat + key [A+S] { MainMenu 'S' } + key [A+T] { MainMenu 'T' } + key [A+U] { BlockUnindent } + key [A+W] { MainMenu 'W' } + key [C+S] { IncrementalSearch } + + key [C+O_C+A] { ToggleAutoIndent } + key [C+O_C+C] { ToggleMatchCase } + key [C+O_C+E] { ToggleTrim } + key [C+O_C+I] { ToggleInsert } +# key [C+O_C+M] { ChangeMode } +# key [C+O_C+M] { ShowMenu 'MChangeMode' } + key [C+O_C+R] { ToggleReadOnly } + key [C+O_C+S] { ToggleSysClipboard } + key [C+O_C+T] { ChangeTabSize } + key [C+O_C+U] { ToggleUndo } + key [C+O_C+W] { ToggleWordWrap } + key [C+O_.] { ToggleShowMarkers } + key [C+O_[] { SetLeftMargin } + key [C+O_\]] { SetRightMargin } + key [C+O_A+[] { ChangeLeftMargin } + key [C+O_A+\]] { ChangeRightMargin } + key [C+O_Tab] { ToggleShowTabs } + key [C+O_C+Tab] { ToggleExpandTabs } + key [C+O_Del] { ToggleDeleteKillTab } + key [C+O_G-Ins] { ToggleInsert } + key [C+O_BackSp] { ToggleBackSpKillTab } + key [C+O_Space] { ToggleIndentWithTabs } + key [C+O_C+BackSp] { ToggleBackSpUnindents } + key [A+-] { MatchBracket } + key [A+=] { HilitMatchBracket } + key [C+Space] { InsPrevLineChar } + key [A+Space] { InsPrevLineToEol } + key [A+F5] { ShowEntryScreen } + key [C+_] { ShowPosition } + key [Center] { MoveLineCenter } + key [C+X] { MovePrevPos } +# key [C+S+A] { ASCIITable } + key [G+*] { LineInsert ; MoveUp; ScrollUp } + +# key [G++] { DumpFold } + key [A+G++] { FoldCreate } + key [A+G+-] { FoldDestroy } + key [G+S++] { FoldPromote } + key [G+S+-] { FoldDemote } + key [C+G++] { FoldOpen } + key [C+G+-] { FoldClose } + key [C+G+*] { FoldOpenNested } + key [C+G+/] { FoldToggleOpenClose } + key [A+G+*] { FoldOpenAll } + key [A+G+/] { FoldCloseAll } + +# key [C+G-Up] { MoveFoldPrev } +# key [C+G-Down] { MoveFoldNext } + +# key [A+C+A] { FileOpen 'BUFFER.CPP' } + + key [C+K] { ShowKey } + key [A+,] { SearchWordPrev } + key [A+.] { SearchWordNext } + key [A+/] { HilitWord } +} + +colorize PLAIN { + SyntaxParser = 'PLAIN'; + + color { + { 'Normal', '7 0' }, + }; +} + +mode PLAIN { + Colorizer = 'PLAIN'; +} + +eventmap LIST { + key [G-Left] { MoveLeft } + key [G-Right] { MoveRight } + key [G-Up] { MoveUp } + key [G-Down] { MoveDown } + key [G-Home] { MoveLineStart } + key [C+G-Home] { MovePageStart } + key [G-End] { MoveLineEnd } + key [C+G-End] { MovePageEnd } + key [G-PgUp] { MovePageUp } + key [C+G-PgUp] { MoveFileStart } + key [G-PgDn] { MovePageDown } + key [C+G-PgDn] { MoveFileEnd } + key [A+G-Up] { ScrollUp } + key [A+G-Down] { ScrollDown } + key [A+G-Left] { ScrollLeft } + key [A+G-Right] { ScrollRight } + + key [Esc] { Cancel } + key [G-Enter] { Activate } +} + +eventmap BUFFERS: LIST { + key [C+F10] { FileClose } + key [F2] { FileSave } +} + +eventmap ROUTINES: LIST { +} + +eventmap MLIST: MODEL { + key [G-Left] { MoveLeft } + key [G-Right] { MoveRight } + key [G-Up] { MoveUp } + key [G-Down] { MoveDown } + key [G-Home] { MoveLineStart } + key [C+G-Home] { MovePageStart } + key [G-End] { MoveLineEnd } + key [C+G-End] { MovePageEnd } + key [G-PgUp] { MovePageUp } + key [C+G-PgUp] { MoveFileStart } + key [G-PgDn] { MovePageDown } + key [C+G-PgDn] { MoveFileEnd } +# key [A+G-Up] { ScrollUp } +# key [A+G-Down] { ScrollDown } +# key [A+G-Left] { ScrollLeft } +# key [A+G-Right] { ScrollRight } + + key [G-Enter] { Activate } +} + +menu DirectoryFile { + item "&Open...\tF3" { FileOpen } + item "&Next\tF6" { FileNext } + item "&Previous\tShift+F6" { FilePrev } + item; + item "&Close\tAlt+Q" { FileClose } + item; + item "E&xit\tAlt+X" { ExitEditor } +} + +menu Navigate { + item "Go &< level\tCtrl+PgUp" { DirGoUp } + item "Go &> level\tCtrl+PgDn" { DirGoDown } + item "Go to &\\\tCtrl+\\" { DirGoRoot } +# item "&/ Goto Dir\t/" { DirGoto } + item "&\\ Goto Dir\t\\" { DirGoto } + item; + item '&A:\\' { DirGoto 'A:\\' } + item '&B:\\' { DirGoto 'B:\\' } + item '&C:\\' { DirGoto 'C:\\' } + item '&D:\\' { DirGoto 'D:\\' } + item '&E:\\' { DirGoto 'E:\\' } + item '&F:\\' { DirGoto 'F:\\' } + item '&G:\\' { DirGoto 'G:\\' } + item '&H:\\' { DirGoto 'H:\\' } + item '&I:\\' { DirGoto 'I:\\' } +} + +menu DirectoryMain { + submenu "&File", DirectoryFile; + submenu "&Navigate", Navigate; + submenu "&Window", Window; + submenu "&Help", Help; +} + +eventmap DIRECTORY: MLIST { + MainMenu = 'DirectoryMain'; + + key [C+G-PgUp] { DirGoUp } + key [C+G-PgDn] { DirGoDown } + key [C+\\] { DirGoRoot } + key [/] { DirGoto } + key [\\] { DirGoto } + + key [A+F] { MainMenu 'F' } + key [A+N] { MainMenu 'N' } + key [A+W] { MainMenu 'W' } +} + +menu Messages { + item "&Close\tAlt+Q" { FileClose } + item; + item "&Next\tF6" { FileNext } + item "&Previous\tShift+F6" { FilePrev } + item; + item "E&xit\tAlt+X" { ExitEditor } +} + +menu MsgMain { + submenu "&Messages", Messages; + submenu "&Window", Window; +} + +eventmap MESSAGES: MLIST { + MainMenu = "MsgMain"; + + key [A+M] { MainMenu 'M' } + key [A+T] { MainMenu 'T' } + key [A+W] { MainMenu 'W' } +} diff --git a/src/sysdep.h b/src/sysdep.h new file mode 100644 index 0000000..f992970 --- /dev/null +++ b/src/sysdep.h @@ -0,0 +1,172 @@ +/* sysdep.h + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#ifndef __SYSDEP_H +#define __SYSDEP_H + +#include +#include +#include +#include +#include +#if defined(AIX) || defined(SCO) || defined(NCR) +#include +#endif +#include +#include +#include +#include +#include +#include + +#ifdef DBMALLOC +#include +#endif + +#if !defined(OS2) && \ + !defined(NT) && \ + !defined(DOSP32) && \ + !defined(LINUX) && \ + !defined(HPUX) && \ + !defined(AIX) && \ + !defined(IRIX) && \ + !defined(SCO) && \ + !defined(SUNOS) && \ + !defined(NCR) +# error Target not supported. +#endif + +#if defined(UNIX) || defined(DJGPP) +# define USE_DIRENT +#endif + +#if defined(USE_DIRENT) // also needs fnmatch +# include +#endif + +#if defined(UNIX) +# include +# include +# if defined(__CYGWIN__) +# include "fnmatch.h" +# else +# include +# endif +# define strnicmp strncasecmp +# define stricmp strcasecmp +# define filecmp strcmp + //# define memicmp strncasecmp // FIX, fails for nulls + extern "C" int memicmp(const void *s1, const void *s2, size_t n); +#endif + +#if defined(OS2) +# include +# if !defined(__TOS_OS2__) +# include +# endif +# include +# include +# if defined(BCPP) || defined(WATCOM) || defined(__TOS_OS2__) +# include +# endif +# if defined(BCPP) +# include +# endif +# define filecmp stricmp +# if !defined(__EMX__) +# define NO_NEW_CPP_FEATURES +# endif +#endif + +#if defined(DOS) || defined(DOSP32) +# include +# include +# include +# include +# define NO_NEW_CPP_FEATURES +# if defined(BCPP) +# include +# endif +# if defined(WATCOM) +# include +# endif +# if defined(DJGPP) +# include +# include +# undef MAXPATH + extern "C" int memicmp(const void *s1, const void *s2, size_t n); +# endif +# define filecmp stricmp +#endif + +#if defined(NT) +# include +# include +# include +# include +# if defined(MSVC) +# include +# endif +# if defined(WATCOM) +# include +# endif +# if defined(BCPP) +# include +# endif +# if defined(MINGW) +# include +# endif +# define filecmp stricmp +# define popen _popen +# define pclose _pclose +#endif + +#ifndef MAXPATH +# define MAXPATH 1024 +#endif + +#ifndef O_BINARY +# define O_BINARY 0 /* defined on OS/2, no difference on unix */ +#endif + +#if defined(OS2) || defined(NT) +# if defined(__EMX__) || defined(WATCOM) || defined(__TOS_OS2__) +# define FAKE_BEGINTHREAD_NULL NULL, +# else +# define FAKE_BEGINTHREAD_NULL +# endif +#endif + +#if !defined(__IBMC__) && !defined(__IBMCPP__) +# define _LNK_CONV +#endif + +#define PT_UNIXISH 0 +#define PT_DOSISH 1 + +#ifndef S_ISDIR // NT, DOS, DOSP32 +# ifdef S_IFDIR +# define S_ISDIR(mode) ((mode) & S_IFDIR) +# else +# define S_ISDIR(mode) ((mode) & _S_IFDIR) +# endif +#endif + +#ifndef S_IWGRP +#define S_IWGRP 0 +#define S_IWOTH 0 +#endif + +#if defined(OS2) || defined(NT) || defined(DOSP32) || defined(DOS) +#define PATHTYPE PT_DOSISH +#else +#define PATHTYPE PT_UNIXISH +#endif + +#endif diff --git a/src/view.cpp b/src/view.cpp new file mode 100644 index 0000000..3d8e331 --- /dev/null +++ b/src/view.cpp @@ -0,0 +1,735 @@ +/* view.cpp + * + * Copyright (c) 1994-1996, Marko Macek + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +#include "fte.h" + +EView *ActiveView = 0; + +extern BufferView *BufferList; + +EView::EView(EModel *AModel) { + if (ActiveView) { + Prev = ActiveView; + Next = ActiveView->Next; + Prev->Next = this; + Next->Prev = this; + } else + Prev = Next = this; + ActiveView = this; + Model = AModel; + NextView = 0; + Port = 0; + MView = 0; + CurMsg = 0; + if (Model) + Model->CreateViewPort(this); +} + +EView::~EView() { + if (Next != this) { + Prev->Next = Next; + Next->Prev = Prev; + if (ActiveView == this) + ActiveView = Next; + } else + ActiveView = 0; + if (MView) + MView->View = 0; + if (Model) + Model->RemoveView(this); + if (Port) + delete Port; +} + +int EView::CanQuit() { + if (Model) + return Model->CanQuit(); + else + return 1; +} + +void EView::FocusChange(int GetFocus) { + if (GetFocus) { + if (Model->View && Model->View->Port) + Model->View->Port->GetPos(); + Model->CreateViewPort(this); + } else { + if (Model) { + Model->RemoveView(this); + delete Port; + Port = 0; + if (Model->View && Model->View->Port) + Model->View->Port->StorePos(); + } + } +} + +void EView::Resize(int Width, int Height) { + if (Port) + Port->Resize(Width, Height); +} + +void EView::SetModel(EModel *AModel) { + Model = AModel; + ActiveModel = Model; +} + +void EView::SelectModel(EModel *AModel) { + if (Model != AModel) { + if (Model) + FocusChange(0); + SetModel(AModel); + if (Model) + FocusChange(1); + } +} + +void EView::SwitchToModel(EModel *AModel) { + if (Model != AModel) { + if (Model) + FocusChange(0); + + AModel->Prev->Next = AModel->Next; + AModel->Next->Prev = AModel->Prev; + + if (Model) { + AModel->Next = Model; + AModel->Prev = Model->Prev; + AModel->Prev->Next = AModel; + Model->Prev = AModel; + } else { + AModel->Next = AModel->Prev = AModel; + } + + SetModel(AModel); + + if (Model) + FocusChange(1); + } +} + +void EView::Activate(int GotFocus) { + if (Model && Model->View != this && Port) { + Model->SelectView(this); + if (GotFocus) { + Port->StorePos(); + } else { + Port->GetPos(); + } + Port->RepaintView(); + if (GotFocus) + ActiveView = this; + } +} + +int EView::GetContext() { + return Model ? Model->GetContext() : 0; +} + +EEventMap *EView::GetEventMap() { + return Model ? Model->GetEventMap() : 0; +} + +int EView::BeginMacro() { + return Model ? Model->BeginMacro() : 0; +} + +int EView::ExecCommand(int Command, ExState &State) { + switch (Command) { + case ExSwitchTo: return SwitchTo(State); + case ExFilePrev: return FilePrev(); + case ExFileNext: return FileNext(); + case ExFileLast: return FileLast(); + case ExFileOpen: return FileOpen(State); + case ExFileOpenInMode: return FileOpenInMode(State); + case ExFileSaveAll: return FileSaveAll(); + + case ExListRoutines: +#ifdef CONFIG_OBJ_ROUTINE + return ViewRoutines(State); +#else + return ErFAIL; +#endif + + case ExDirOpen: +#ifdef CONFIG_OBJ_DIRECTORY + return DirOpen(State); +#else + return ErFAIL; +#endif + +#ifdef CONFIG_OBJ_MESSAGES + case ExViewMessages: return ViewMessages(State); + case ExCompile: return Compile(State); + case ExRunCompiler: return RunCompiler(State); + case ExCompilePrevError: return CompilePrevError(State); + case ExCompileNextError: return CompileNextError(State); +#else + case ExViewMessages: return ErFAIL; + case ExCompile: return ErFAIL; + case ExCompilePrevError: return ErFAIL; + case ExCompileNextError: return ErFAIL; +#endif + + case ExViewBuffers: return ViewBuffers(State); + + case ExShowKey: return ShowKey(State); + case ExToggleSysClipboard: return ToggleSysClipboard(State); + case ExSetPrintDevice: return SetPrintDevice(State); + case ExShowVersion: return ShowVersion(); + case ExViewModeMap: return ViewModeMap(State); + case ExClearMessages: return ClearMessages(); + +#ifdef CONFIG_TAGS + case ExTagNext: return TagNext(this); + case ExTagPrev: return TagPrev(this); + case ExTagPop: return TagPop(this); + case ExTagClear: TagClear(); return 1; + case ExTagLoad: return TagLoad(State); +#endif + case ExShowHelp: return SysShowHelp(State, 0); + case ExConfigRecompile: return ConfigRecompile(State); + case ExRemoveGlobalBookmark:return RemoveGlobalBookmark(State); + case ExGotoGlobalBookmark: return GotoGlobalBookmark(State); + case ExPopGlobalBookmark: return PopGlobalBookmark(); + } + return Model ? Model->ExecCommand(Command, State) : 0; +} + +void EView::HandleEvent(TEvent &Event) { + if (Model) + Model->HandleEvent(Event); + if (Port) + Port->HandleEvent(Event); + if (Event.What == evCommand) { + switch (Event.Msg.Command) { + case cmDroppedFile: + { + char *file = (char *)Event.Msg.Param2; + +#ifdef CONFIG_OBJ_DIRECTORY + if (IsDirectory(file)) + OpenDir(file); +#endif + MultiFileLoad(0, file, NULL, this); + } + break; + } + } +} + +void EView::UpdateView() { + if (Port) + Port->UpdateView(); +} + +void EView::RepaintView() { + if (Port) + Port->RepaintView(); +} + +void EView::UpdateStatus() { + if (Port) + Port->UpdateStatus(); +} + +void EView::RepaintStatus() { + if (Port) + Port->RepaintStatus(); +} + +void EView::DeleteModel(EModel *M) { + EView *V; + EModel *M1; + char s[256]; + + if (M == 0) + return; + + M->GetName(s, sizeof(s)); + Msg(S_INFO, "Closing %s.", s); + + V = ActiveView = this; + while (V) { + M1 = V->Model; + if (M1 == M) { + if (M->Next != M) + V->SelectModel(M->Next); + else + V->SelectModel(0); + } + V = V->Next; + if (V == ActiveView) + break; + } + delete M; + SetMsg(0); + return; +} + +///////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////// + +int EView::FilePrev() { + if (Model) { + SelectModel(Model->Prev); + return 1; + } + return 0; +} + +int EView::FileNext() { + if (Model) { + SelectModel(Model->Next); + return 1; + } + return 0; +} + +int EView::FileLast() { + if (Model) { + SwitchToModel(Model->Next); + return 1; + } + return 0; +} + +int EView::SwitchTo(ExState &State) { + EModel *M; + int No; + + if (State.GetIntParam(this, &No) == 0) { + char str[10] = ""; + + if (MView->Win->GetStr("Obj.Number", sizeof(str), str, 0) == 0) return 0; + No = atoi(str); + } + M = Model; + while (M) { + if (M->ModelNo == No) { + SwitchToModel(M); + return 1; + } + M = M->Next; + if (M == Model) + return 0; + } + return 0; +} + + +int EView::FileSaveAll() { + EModel *M = Model; + while (M) { + if (M->GetContext() == CONTEXT_FILE) { + EBuffer *B = (EBuffer *)M; + if (B->Modified) { + SwitchToModel(B); + if (B->Save() == 0) return 0; + } + } + M = M->Next; + if (M == Model) break; + } + return 1; +} + +int EView::FileOpen(ExState &State) { + char FName[MAXPATH]; + + if (State.GetStrParam(this, FName, sizeof(FName)) == 0) { + if (GetDefaultDirectory(Model, FName, sizeof(FName)) == 0) + return 0; + if (MView->Win->GetFile("Open file", sizeof(FName), FName, HIST_PATH, GF_OPEN) == 0) return 0; + } + + if( strlen( FName ) == 0 ) return 0; + +#ifdef CONFIG_OBJ_DIRECTORY + if (IsDirectory(FName)) + return OpenDir(FName); +#endif + return MultiFileLoad(0, FName, NULL, this); +} + +int EView::FileOpenInMode(ExState &State) { + char Mode[32] = ""; + char FName[MAXPATH]; + + if (State.GetStrParam(this, Mode, sizeof(Mode)) == 0) + if (MView->Win->GetStr("Mode", sizeof(Mode), Mode, HIST_SETUP) != 1) return 0; + + if (FindMode(Mode) == 0) { + MView->Win->Choice(GPC_ERROR, "Error", 1, "O&K", "Invalid mode '%s'", Mode); + return 0; + } + + if (GetDefaultDirectory(Model, FName, sizeof(FName)) == 0) + return 0; + if (State.GetStrParam(this, FName, sizeof(FName)) == 0) + if (MView->Win->GetFile("Open file", sizeof(FName), FName, HIST_PATH, GF_OPEN) == 0) return 0; +#ifdef CONFIG_OBJ_DIRECTORY + { + int l = strlen(FName); + + if (l > 1 && ISSLASH(FName[l - 1])) + return OpenDir(FName); + } +#endif + + if( strlen( FName ) == 0 ) return 0; + + return MultiFileLoad(0, FName, Mode, this); +} + +int EView::SetPrintDevice(ExState &State) { + char Dev[MAXPATH]; + + strcpy(Dev, PrintDevice); + if (State.GetStrParam(this, Dev, sizeof(Dev)) == 0) + if (MView->Win->GetStr("Print to", sizeof(Dev), Dev, HIST_SETUP) == 0) return 0; + + strcpy(PrintDevice, Dev); + return 1; +} + +int EView::ToggleSysClipboard(ExState &/*State*/) { + SystemClipboard = SystemClipboard ? 0 : 1; + Msg(S_INFO, "SysClipboard is now %s.", SystemClipboard ? "ON" : "OFF"); + return 1; +} + +int EView::ShowKey(ExState &/*State*/) { + char buf[100]; + KeySel ks; + + ks.Mask = 0; + ks.Key = MView->Win->GetChar(0); + + GetKeyName(buf, ks); + Msg(S_INFO, "Key: '%s' - '%8X'", buf, ks.Key); + return 1; +} + +void EView::Msg(int level, const char *s, ...) { + va_list ap; + + va_start(ap, s); + vsprintf(msgbuftmp, s, ap); + va_end(ap); + + if (level != S_BUSY) + SetMsg(msgbuftmp); +} + +void EView::SetMsg(char *Msg) { + if (CurMsg) + free(CurMsg); + CurMsg = 0; + if (Msg && strlen(Msg)) + CurMsg = strdup(Msg); + if (CurMsg && Msg && MView) { + TDrawBuffer B; + char SColor; + int Cols, Rows; + + MView->ConQuerySize(&Cols, &Rows); + + if (MView->IsActive()) + SColor = hcStatus_Active; + else + SColor = hcStatus_Normal; + + MoveChar(B, 0, Cols, ' ', SColor, Cols); + MoveStr(B, 0, Cols, CurMsg, SColor, Cols); + if (MView->Win->GetStatusContext() == MView) + MView->ConPutBox(0, Rows - 1, Cols, 1, B); + //printf("%s\n", Msg); + } +} + +int EView::ViewBuffers(ExState &/*State*/) { + if (BufferList == 0) { + BufferList = new BufferView(0, &ActiveModel); + SwitchToModel(BufferList); + } else { + BufferList->UpdateList(); + BufferList->Row = 1; + SwitchToModel(BufferList); + return 1; + } + return 0; +} + +#ifdef CONFIG_OBJ_ROUTINE +int EView::ViewRoutines(ExState &/*State*/) { + //int rc = 1; + //RoutineView *routines; + EModel *M; + EBuffer *Buffer; + + M = Model; + if (M->GetContext() != CONTEXT_FILE) + return 0; + Buffer = (EBuffer *)M; + + if (Buffer->Routines == 0) { + if (BFS(Buffer, BFS_RoutineRegexp) == 0) { + MView->Win->Choice(GPC_ERROR, "Error", 1, "O&K", "No routine regexp."); + return 0; + } + Buffer->Routines = new RoutineView(0, &ActiveModel, Buffer); + if (Buffer->Routines == 0) + return 0; + } else { + Buffer->Routines->UpdateList(); + } + SwitchToModel(Buffer->Routines); + return 1; +} +#endif + +#ifdef CONFIG_OBJ_DIRECTORY +int EView::DirOpen(ExState &State) { + char Path[MAXPATH]; + + if (State.GetStrParam(this, Path, sizeof(Path)) == 0) + if (GetDefaultDirectory(Model, Path, sizeof(Path)) == 0) + return 0; + return OpenDir(Path); +} + +int EView::OpenDir(char *Path) { + char XPath[MAXPATH]; + EDirectory *dir = 0; + + if (ExpandPath(Path, XPath) == -1) + return 0; + { + EModel *x = Model; + while (x) { + if (x->GetContext() == CONTEXT_DIRECTORY) { + if (filecmp(((EDirectory *)x)->Path, XPath) == 0) + { + dir = (EDirectory *)x; + break; + } + } + x = x->Next; + if (x == Model) + break; + } + } + if (dir == 0) + dir = new EDirectory(0, &ActiveModel, XPath); + SelectModel(dir); + return 1; +} +#endif + +#ifdef CONFIG_OBJ_MESSAGES +int EView::Compile(ExState &State) { + static char Cmd[256] = ""; + char Command[256] = ""; + + if (CompilerMsgs != 0 && CompilerMsgs->Running) { + Msg(S_INFO, "Already running..."); + return 0; + } + + if (State.GetStrParam(this, Command, sizeof(Command)) == 0) { + if (Model->GetContext() == CONTEXT_FILE) { + EBuffer *B = (EBuffer *)Model; + if (BFS(B, BFS_CompileCommand) != 0) + strcpy(Cmd, BFS(B, BFS_CompileCommand)); + } + if (Cmd[0] == 0) + strcpy(Cmd, CompileCommand); + + if (MView->Win->GetStr("Compile", sizeof(Cmd), Cmd, HIST_COMPILE) == 0) return 0; + + strcpy(Command, Cmd); + } else { + if (MView->Win->GetStr("Compile", sizeof(Command), Command, HIST_COMPILE) == 0) return 0; + } + return Compile(Command); +} + +int EView::RunCompiler(ExState &State) { + char Command[256] = ""; + + if (CompilerMsgs != 0 && CompilerMsgs->Running) { + Msg(S_INFO, "Already running..."); + return 0; + } + + if (State.GetStrParam(this, Command, sizeof(Command)) == 0) { + if (Model->GetContext() == CONTEXT_FILE) { + EBuffer *B = (EBuffer *)Model; + if (BFS(B, BFS_CompileCommand) != 0) + strcpy(Command, BFS(B, BFS_CompileCommand)); + } + if (Command[0] == 0) + strcpy(Command, CompileCommand); + } + return Compile(Command); +} + +int EView::Compile(char *Command) { + char Dir[MAXPATH] = ""; + EMessages *msgs; + + if (CompilerMsgs != 0) { + strcpy(Dir, CompilerMsgs->Directory); + CompilerMsgs->RunPipe(Dir, Command); + msgs = CompilerMsgs; + } else { + if (GetDefaultDirectory(Model, Dir, sizeof(Dir)) == 0) + return 0; + + msgs = new EMessages(0, &ActiveModel, Dir, Command); + } + SwitchToModel(msgs); + return 1; +} + +int EView::ViewMessages(ExState &/*State*/) { + if (CompilerMsgs != 0) { + SwitchToModel(CompilerMsgs); + return 1; + } + return 0; +} + +int EView::CompilePrevError(ExState &/*State*/) { + if (CompilerMsgs != 0) + return CompilerMsgs->CompilePrevError(this); + return 0; +} + +int EView::CompileNextError(ExState &/*State*/) { + if (CompilerMsgs != 0) + return CompilerMsgs->CompileNextError(this); + return 0; +} +#endif + +int EView::ShowVersion() { + MView->Win->Choice(0, "About", 1, "O&K", PROGRAM " " VERSION " " COPYRIGHT); + return 1; +} + +int EView::ViewModeMap(ExState &/*State*/) { + if (TheEventMapView != 0) + TheEventMapView->ViewMap(GetEventMap()); + else + (void)new EventMapView(0, &ActiveModel, GetEventMap()); + if (TheEventMapView != 0) + SwitchToModel(TheEventMapView); + else + return 0; + return 1; +} + +int EView::ClearMessages() { + if (CompilerMsgs != 0 && CompilerMsgs->Running) { + Msg(S_INFO, "Running..."); + return 0; + } + if (CompilerMsgs != 0) { + CompilerMsgs->FreeErrors(); + CompilerMsgs->UpdateList(); + } + return 1; +} + +#ifdef CONFIG_TAGS +int EView::TagLoad(ExState &State) { + char Tag[MAXPATH]; + char FullTag[MAXPATH]; + + if (ExpandPath("tags", Tag) == -1) + return 0; + if (State.GetStrParam(this, Tag, sizeof(Tag)) == 0) + if (MView->Win->GetFile("Load tags", sizeof(Tag), Tag, HIST_TAGFILES, GF_OPEN) == 0) return 0; + + if (ExpandPath(Tag, FullTag) == -1) + return 0; + + if (!FileExists(FullTag)) { + Msg(S_INFO, "Tag file '%s' not found.", FullTag); + return 0; + } + + return ::TagLoad(FullTag); +} +#endif + +int EView::ConfigRecompile(ExState &State) { + if (ConfigSourcePath == 0 || ConfigFileName[0] == 0) { + Msg(S_ERROR, "Cannot recompile (must use external configuration)."); + return 0; + } + + char command[1024]; + + strcpy(command, "cfte "); + strcat(command, ConfigSourcePath); + strcat(command, " "); +#ifdef UNIX + if (ExpandPath("~/.fterc", command + strlen(command)) != 0) + return 0; +#else + strcat(command, ConfigFileName); +#endif + return Compile(command); +} + +int EView::RemoveGlobalBookmark(ExState &State) { + char name[256] = ""; + + if (State.GetStrParam(this, name, sizeof(name)) == 0) + if (MView->Win->GetStr("Remove Global Bookmark", sizeof(name), name, HIST_BOOKMARK) == 0) return 0; + if (markIndex.remove(name) == 0) { + Msg(S_ERROR, "Error removing global bookmark %s.", name); + return 0; + } + return 1; +} + +int EView::GotoGlobalBookmark(ExState &State) { + char name[256] = ""; + + if (State.GetStrParam(this, name, sizeof(name)) == 0) + if (MView->Win->GetStr("Goto Global Bookmark", sizeof(name), name, HIST_BOOKMARK) == 0) return 0; + if (markIndex.view(this, name) == 0) { + Msg(S_ERROR, "Error locating global bookmark %s.", name); + return 0; + } + return 1; +} +int EView::PopGlobalBookmark() { + if (markIndex.popMark(this) == 0) { + Msg(S_INFO, "Bookmark stack empty."); + return 0; + } + return 1; +} + +int EView::GetStrVar(int var, char *str, int buflen) { + //switch (var) { + //} + return Model->GetStrVar(var, str, buflen); +} + +int EView::GetIntVar(int var, int *value) { + //switch (var) { + //} + return Model->GetIntVar(var, value); +}