Hi there,I'm hereby reporting back after many, many years of lurking. I've whipped up a couple of small patches against 1.7.901, maybe you'll find them useful:
* yadex-gcc4.patch:Just a few minor changes (mainly in scripts/m7) to make Yadex compile on my Fedora 13 box: - getc and putc seem to be defined as preprocessor macros, so they can't be used as identifiers. As a quick workaround I just undefined the macros.
- The original getc and putc are in the root namespace, not in std::. - Missing include (for UCHAR_MAX) in m7/input_buf.h - Empty #elif in src/gfx.cc * yadex-makedepend.patch:I couldn't find the "makedepend" tool in F13, so the yadex.dep rule always silently created an empty file (the error messages were hidden by the redirection of stderr). So I've added an alternative way to create the dependencies using gcc.
* yadex-readline.patch:Fancy new feature: If available, use GNU readline for CLI input. Advantages: full line editing, history and context-sensitive completion.
* yadex-close-window.patch:This fixes a very annoying problem: Yadex crashes if any graphical window is closed using the X button. The patch simulates an ESC keystroke if the window is closed, so the window can be closed gracefully (after asking the user if he wants to discard his unsaved changes).
Cheers, Ingo
commit 0a199d735e8ba1271576b82d77ee5da0993f9fbe Author: Ingo van Lil <inguin@xxxxxx> Date: Thu Sep 2 23:58:53 2010 +0200 Gracefully close window when the 'X' button is pressed. diff --git a/src/gfx.cc b/src/gfx.cc index 638e635..90182de 100644 --- a/src/gfx.cc +++ b/src/gfx.cc @@ -118,6 +118,7 @@ static pcolour_t *app_colour = 0; // Pixel values for the app. colours static int DrawingMode = 0; // 0 = copy, 1 = xor static int LineThickness = 0; // 0 = thin, 1 = thick int text_dot = 0; // DrawScreenText() debug flag +Atom wm_delete; #endif static acolour_t colour_stack[4]; static int colour_stack_pointer = 0; @@ -471,6 +472,10 @@ int InitGfx (void) | ExposureMask | StructureNotifyMask); + // register for message from window manager if the window is closed + wm_delete = XInternAtom(dpy, "WM_DELETE_WINDOW", False); + XSetWMProtocols(dpy, win, &wm_delete, 1); + /* * Possibly load and query the font */ diff --git a/src/gfx.h b/src/gfx.h index 0308670..d8709ef 100644 --- a/src/gfx.h +++ b/src/gfx.h @@ -96,6 +96,7 @@ extern int win_bpp; // The depth of win in bytes extern int x_server_big_endian; // Is the X server big-endian ? extern int ximage_bpp; // Number of bytes per pixels in XImages extern int ximage_quantum; // Pad XImage lines to a mult of that many B. +extern Atom wm_delete; // window delete message from window manager #endif // ifdef X_PROTOCOL #endif // ifdef Y_X11 extern int text_dot; // DrawScreenText()/DrawScreenString() debug flag diff --git a/src/input.cc b/src/input.cc index 8a3b582..9425fb6 100644 --- a/src/input.cc +++ b/src/input.cc @@ -414,6 +414,12 @@ switch (ev.type) #endif break; } + + case ClientMessage: + if ((Atom)ev.xclient.data.l[0] == wm_delete) + // window has been closed, simulate ESC keypress + is.key = YK_ESC; + break; } /* switch (ev.type) */ }
commit 06800386415e4b701212a10b14c49ee796f50ca8 Author: Ingo van Lil <inguin@xxxxxx> Date: Wed Sep 1 21:31:43 2010 +0200 gcc4 build fixes. diff --git a/scripts/m7/input_buf.h b/scripts/m7/input_buf.h index e2d5e4c..d285fa8 100644 --- a/scripts/m7/input_buf.h +++ b/scripts/m7/input_buf.h @@ -25,6 +25,7 @@ this program; if not, write to the Free Software Foundation, Inc., #include <stddef.h> #include <stdio.h> +#include <limits.h> #include <string> diff --git a/scripts/m7/input_file.h b/scripts/m7/input_file.h index e8f6247..a1da434 100644 --- a/scripts/m7/input_file.h +++ b/scripts/m7/input_file.h @@ -116,7 +116,7 @@ inline int Input_file::peekc () { if (cnext == NOCHAR) { - cnext = std::getc (fp); + cnext = ::getc (fp); if (c == '\n') { nextline_++; diff --git a/scripts/m7/output.h b/scripts/m7/output.h index ca8911c..3b0d9b2 100644 --- a/scripts/m7/output.h +++ b/scripts/m7/output.h @@ -28,6 +28,13 @@ this program; if not, write to the Free Software Foundation, Inc., #include <string> +#ifdef putc +# undef putc +#endif + +#ifdef getc +# undef getc +#endif class Output { diff --git a/scripts/m7/output_file.h b/scripts/m7/output_file.h index 539f0ee..5cbdc20 100644 --- a/scripts/m7/output_file.h +++ b/scripts/m7/output_file.h @@ -87,7 +87,7 @@ inline int Output_file::putc (char c) bol = false; } - int r = std::putc (c, fp); + int r = ::putc (c, fp); if (r != EOF) col_++; if (c == '\n') diff --git a/src/gfx.cc b/src/gfx.cc index 370ed1b..638e635 100644 --- a/src/gfx.cc +++ b/src/gfx.cc @@ -310,7 +310,7 @@ int InitGfx (void) win_vis_id = vis_info->visualid; #if defined _cplusplus || defined __cplusplus win_vis_class = vis_info->c_class; -#elif +#else win_vis_class = vis_info->class; #endif win_ncolours = vis_info->colormap_size;
commit 58917624ac919ee5be7b1d3c1fa5bbbc93d99cab Author: Ingo van Lil <inguin@xxxxxx> Date: Tue Aug 31 21:08:37 2010 +0200 Use gcc (if available) to generate yadex.dep file. diff --git a/GNUmakefile b/GNUmakefile index 61c4652..c8bb3bc 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -767,6 +767,12 @@ $(OBJDIR)/files_share.man: $(OBJDIR)/config.share $(MAKEFILE) cache/yadex.dep: $(SRC_NON_GEN) src/config.h @echo "Generating $@" @test -d cache || mkdir cache +ifeq ($(CC), gcc) + @gcc -MM $(CFLAGS) $(SRC_NON_GEN) >$(@D)/.$(@F) + @sed 's,^[^ ],$(OBJDIR)/,' $(@D)/.$(@F) >$@ + @sed 's,^[^ ],$(DOBJDIR)/,' $(@D)/.$(@F) >>$@ + @rm $(@D)/.$(@F) +else @makedepend -f- -Y -Iatclib $(SRC_NON_GEN) 2>/dev/null \ | $(AWK) 'sub (/^src/, "") == 1 { \ print "'$(OBJDIR)'" $$0; \ @@ -774,6 +780,7 @@ cache/yadex.dep: $(SRC_NON_GEN) src/config.h next; \ }' >$(@D)/.$(@F) @mv -f $(@D)/.$(@F) $@ +endif cache/copyright.man: $(MAKEFILE) scripts/copyright docsrc/copyright @echo "Generating $@" @@ -854,7 +861,7 @@ cache/uptodate: scripts/youngest $(SRC_NON_GEN) # To compile the modules of Yadex # (normal and debugging versions) -include cache/yadex.dep +-include cache/yadex.dep # It's simpler to copy config.cc into src/ than to have a # compilation rule for just one file.
commit 78a996bae396724eeb0dd284829348926482ce49 Author: Ingo van Lil <inguin@xxxxxx> Date: Wed Sep 1 21:10:40 2010 +0200 Use readline for CLI input. diff --git a/GNUmakefile b/GNUmakefile index c8bb3bc..f109a1f 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -134,20 +134,20 @@ MODULES_YADEX = \ macro memory menubar menu \ mkpalette mouse names nop \ objects objinfo oldmenus palview \ - patchdir pic2img prefer s_centre \ - s_door s_lift s_linedefs s_merge \ - s_misc s_prop s_slice s_split \ - s_swapf s_vertices sanity scrnshot \ - selbox selectn selpath selrect \ - serialnum spritdir sticker swapmem \ - t_centre t_flags t_prop t_spin \ - textures things trace v_centre \ - v_merge v_polyg vectext verbmsg \ - version wadfile wadlist wadnamec \ - wadres wads wads2 warn \ - windim x_centre x_exchng x_hover \ - x_mirror x_rotate x11 xref \ - yadex ytime + patchdir pic2img prefer readline \ + s_centre s_door s_lift s_linedefs \ + s_merge s_misc s_prop s_slice \ + s_split s_swapf s_vertices sanity \ + scrnshot selbox selectn selpath \ + selrect serialnum spritdir sticker \ + swapmem t_centre t_flags t_prop \ + t_spin textures things trace \ + v_centre v_merge v_polyg vectext \ + verbmsg version wadfile wadlist \ + wadnamec wadres wads wads2 \ + warn windim x_centre x_exchng \ + x_hover x_mirror x_rotate x11 \ + xref yadex ytime # All the modules of Atclib without path or extension. MODULES_ATCLIB = \ @@ -288,6 +288,11 @@ SRC = $(filter-out src/config.cc, $(SRC_YADEX)) \ # The files on which youngest is run. SRC_NON_GEN = $(filter-out src/credits.cc src/prefix.cc src/version.cc, $(SRC)) +LIBS = -lX11 -lm -lc +ifeq ($(HAVE_READLINE), 1) + LIBS += -lreadline +endif + # The object files OBJ_YADEX = $(addprefix $(OBJDIR)/, $(addsuffix .o, $(MODULES_YADEX))) DOBJ_YADEX = $(addprefix $(DOBJDIR)/, $(addsuffix .o, $(MODULES_YADEX))) @@ -497,7 +502,7 @@ yadex: $(OBJDIR)/yadex $(OBJDIR)/yadex: $(OBJ_YADEX) $(OBJ_ATCLIB) $(MAKEFILE) @echo "** Linking Yadex" $(CXX) $(LDFLAGS) -o $@ $(OBJ_YADEX) $(OBJ_ATCLIB) \ - $(X11LD) -lX11 -lm -lc + $(X11LD) $(LIBS) .PHONY: test test: diff --git a/configure b/configure index 60c2afa..4ef2a65 100755 --- a/configure +++ b/configure @@ -36,6 +36,7 @@ HAVE_INTTYPES= HAVE_NANOSLEEP= HAVE_SNPRINTF= HAVE_USLEEP= +HAVE_READLINE= INTERFACE=x11 # "bgi" or "x11" (only "x11" is maintained) INTTYPES= LDFLAGS= @@ -176,6 +177,7 @@ genh () { genbool NANOSLEEP genbool SNPRINTF genbool USLEEP + genbool READLINE [ -z "$INTTYPES" ] || printf '\n%s\n' "$INTTYPES" echo echo 'extern const char *yadex_etc_path[];' @@ -447,6 +449,23 @@ int main (int argc, char *argv[]) ' || true # +# Do we have readline() ? +# +LDFLAGS_OLD="$LDFLAGS" +LDFLAGS="$LDFLAGS -lreadline" +check "for readline" HAVE_READLINE ' +#include <stdio.h> +#include <readline/readline.h> +#include <readline/history.h> +int main (int argc, char *argv[]) +{ + add_history("test"); + return 0; +} +' || true +LDFLAGS="$LDFLAGS_OLD" + +# # Look for a C++ compiler # # We try "g++" first, then "c++", then "cxx". @@ -872,6 +891,7 @@ echo generating $BUILDDIR/Makefile.config echo "HAVE_NANOSLEEP = $HAVE_NANOSLEEP" echo "HAVE_SNPRINTF = $HAVE_SNPRINTF" echo "HAVE_USLEEP = $HAVE_USLEEP" + echo "HAVE_READLINE = $HAVE_READLINE" echo "INTERFACE = $INTERFACE" echo "LDFLAGS = $LDFLAGS" echo "MANDIR = $MANDIR" diff --git a/src/readline.cc b/src/readline.cc new file mode 100644 index 0000000..0df9c4d --- /dev/null +++ b/src/readline.cc @@ -0,0 +1,360 @@ +/* + * readline.cc + * Command line interface input function. + */ + + +/* +This file is part of Yadex. + +Yadex incorporates code from DEU 5.21 that was put in the public domain in +1994 by Raphaël Quinet and Brendon Wyber. + +The rest of Yadex is Copyright © 1997-2003 André Majorel and others. + +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free Software +Foundation; either version 2 of the License, or (at your option) any later +version. + +This program is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +this program; if not, write to the Free Software Foundation, Inc., 59 Temple +Place, Suite 330, Boston, MA 02111-1307, USA. +*/ + + +#include "yadex.h" + +#if defined(Y_READLINE) + +#include <string.h> +#include <readline/readline.h> +#include <readline/history.h> + +#include "wadfile.h" +#include "wadlist.h" +#include "wadres.h" +#include "levels.h" +#include "lumpdir.h" +#include "patchdir.h" + +// completion generators for various command arguments +static rl_compentry_func_t *c_filename = rl_filename_completion_function; +static rl_compentry_func_t c_wadentry; +static rl_compentry_func_t c_wadfile; +static rl_compentry_func_t c_levelname; +static rl_compentry_func_t c_spritename; +static rl_compentry_func_t c_flatname; +static rl_compentry_func_t c_patchname; +static rl_compentry_func_t c_texname; + +#define MAX_ARGS 2 + +struct command { + const char *name; + const char *shortcut; + rl_compentry_func_t *completers[MAX_ARGS]; +}; + +// all commands and their argument completers +static struct command commands[] = { + { "build", "b", { c_filename } }, + { "create", "c", {} }, + { "dump", "d", { c_wadentry, c_filename } }, + { "dump_linedef_types", " ", {} }, + { "edit", "e", { c_levelname } }, + { "group", "g", {} }, + { "insert", "i", { c_filename, c_wadentry } }, + { "help", "h", {} }, + { "list", "l", { c_wadfile, c_filename } }, + { "master", "m", { c_filename } }, + { "make_gimp_palette", " ", { c_filename } }, + { "make_palette_ppm", " ", { c_filename } }, + { "quit", "q", {} }, + { "read", "r", { c_filename } }, + { "save", "s", { c_wadentry, c_filename } }, + { "set", " ", {} }, + { "view", "v", { c_spritename } }, + { "viewflat", " ", { c_flatname } }, + { "viewpal", " ", {} }, + { "viewpat", " ", { c_patchname } }, + { "viewtex", " ", { c_texname } }, + { "wads", "w", {} }, + { "xtract", "x", { c_wadentry, c_filename } }, +}; + +// completion generator: command names +static char *command_generator (const char *text, int state) +{ + static size_t list_index; + static size_t len; + + if (state == 0) + { + list_index = 0; + len = strlen (text); + } + + while (list_index < sizeof (commands) / sizeof (command)) + { + const char *cmd = commands[list_index].name; + list_index++; + if (strncmp (cmd, text, len) == 0) + return strdup (cmd); + if (strcmp (text, "?") == 0 && strcmp (cmd, "help") == 0) + return strdup (cmd); + } + return NULL; +} + +// perform completion for the n-th argument of a given command +static char **argument_completion (const char *text, const char *cmd, int arg) +{ + if (arg >= MAX_ARGS) + return NULL; + + for (size_t i = 0; i < sizeof (commands) / sizeof (command); i++) + { + const struct command *command = &commands[i]; + if (strcasecmp (cmd, command->name) == 0 || + strcasecmp (cmd, command->shortcut) == 0) + { + if (command->completers[arg] != NULL) + return rl_completion_matches (text, command->completers[arg]); + break; + } + } + return NULL; +} + +// global command line completion function +static char **yadex_completion (const char *text, int start, int end) +{ + char **matches = NULL; + char *input = strdup (rl_line_buffer); + + // find the command and the token position of the text to complete + char *token = strtok (input, " "); + char *cmd = token; + int arg = 0; + while (token != NULL && (token - input) < start) + { + token = strtok (NULL, " "); + arg++; + } + + if (arg == 0) + // first token: command + matches = rl_completion_matches (text, command_generator); + else + // later token: argument + matches = argument_completion (text, cmd, arg - 1); + + free (input); + rl_attempted_completion_over = 1; + return matches; +} + +char *ReadLine (const char *prompt) +{ + rl_readline_name = "yadex"; + rl_attempted_completion_function = yadex_completion; + + char *input = readline(prompt); + if (input && input[0]) + add_history(input); + return input; +} + +// completion generator: WAD directory entries +static char *c_wadentry (const char *text, int state) +{ + static MDirPtr entry; + static size_t len; + + if (state == 0) + { + entry = MasterDir; + len = strlen (text); + } + + if (len > WAD_NAME) + return NULL; + + while (entry != 0) + { + MDirPtr e = entry; + entry = entry->next; + if (strncasecmp (e->dir.name, text, len) == 0) + return strdup (e->dir.name); + } + return NULL; +} + +// completion generator: WAD file names +static char *c_wadfile (const char *text, int state) +{ + static size_t len; + + if (state == 0) + { + wad_list.rewind(); + len = strlen (text); + } + + const Wad_file *wf; + while (wad_list.get (wf)) + { + if (strncmp (wf->pathname (), text, len) == 0) + return strdup (wf->pathname ()); + } + return NULL; +} + +// completion generator: level names +static char *c_levelname (const char *text, int state) +{ + static MDirPtr entry; + static size_t len; + + if (state == 0) + { + entry = MasterDir; + len = strlen (text); + } + + if (len > WAD_NAME) + return NULL; + + while (entry != 0) + { + MDirPtr e = entry; + entry = entry->next; + if (levelname2levelno (e->dir.name) && + strncasecmp (e->dir.name, text, len) == 0) + return strdup (e->dir.name); + } + return NULL; +} + +// completion generator: sprite names +static char *c_spritename (const char *text, int state) +{ + static Lump_list list; + static size_t n; + static size_t len; + + if (state == 0) + { + Wad_res wad_res (&MasterDir); + wad_res.sprites.list (list); + n = 0; + len = strlen (text); + } + + while (n < list.size()) + { + const char *name = list.data()[n++]; + if (strncasecmp (name, text, len) == 0) + return strdup (name); + } + return NULL; +} + +// completion generator: flat names +static char *c_flatname (const char *text, int state) +{ + static size_t n; + static size_t len; + + if (state == 0) + { + n = 0; + len = strlen (text); + } + + ReadFTextureNames (); + char *res = NULL; + while (n < NumFTexture) + { + const char *name = flat_list[n++].name; + if (strncasecmp (name, text, len) == 0) + { + res = strdup (name); + break; + } + } + ForgetFTextureNames (); + return res; +} + +// completion generator: patch names +static char *c_patchname (const char *text, int state) +{ + static Patch_list list; + static size_t n; + static size_t len; + + if (state == 0) + { + patch_dir.refresh (MasterDir); + patch_dir.list (list); + n = 0; + len = strlen (text); + } + + while (n < list.size()) + { + const char *name = list.data()[n++]; + if (strncasecmp (name, text, len) == 0) + return strdup (name); + } + return NULL; +} + +// completion generators: texture names +static char *c_texname (const char *text, int state) +{ + static int n; + static size_t len; + + if (state == 0) + { + patch_dir.refresh (MasterDir); + n = 0; + len = strlen (text); + } + + ReadWTextureNames(); + char *res = NULL; + while (n < NumWTexture) + { + const char *name = WTexture[n++]; + if (strncasecmp (name, text, len) == 0) + { + res = strdup (name); + break; + } + } + ForgetWTextureNames(); + return res; +} + +#else + +// GNU readline not available; fall back to fgets() +char *ReadLine (const char *prompt) +{ + char input[120]; + printf ("%s", prompt); + if (fgets (input, sizeof input, stdin)) + return strdup(input); + else + return NULL; +} + +#endif diff --git a/src/yadex.cc b/src/yadex.cc index c5ce2bb..dd593d0 100644 --- a/src/yadex.cc +++ b/src/yadex.cc @@ -55,7 +55,6 @@ Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "wadres.h" #include "wads2.h" - /* * Constants (declared in yadex.h) */ @@ -672,15 +671,17 @@ if (Debug && logfile != NULL) static void MainLoop () { -char input[120]; +char *input = NULL; char *com, *out; FILE *file, *raw; for (;;) { /* get the input */ - printf ("yadex: "); - if (! fgets (input, sizeof input, stdin)) + if (input != NULL) + free (input); + input = ReadLine("yadex: "); + if (input == NULL) { puts ("q"); break; diff --git a/src/yadex.h b/src/yadex.h index 55ee107..1867ceb 100644 --- a/src/yadex.h +++ b/src/yadex.h @@ -502,6 +502,9 @@ const char *GetSectorTypeLongName (int); // nop.cc void nop (...); +// readline.cc +char *ReadLine (const char *prompt); + // s_door.cc (previously in objects.cc) void MakeDoorFromSector (int); /* SWAP! */