diff --git a/ChangeLog b/ChangeLog index f7a50d5..6b4a18e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -4166,3 +4166,31 @@ Thu May 24 00:14:54 PDT 2001 Michael Jennings broken in Emacs (*grumble*). Works in gvim though. ------------------------------------------------------------------------------- +Mon Jun 11 17:49:55 PDT 2001 Michael Jennings + + Okay, first off, I removed 3 scaled backgrounds. See www.kainx.org or + my post to enlightenment-devel for details. + + Second, I redid the default bindings for the mouse wheel. Basically, + the wheel alone will scroll by pages. Ctrl+wheel will scroll by pages + in groups of 5. Shift+wheel will scroll by a single line. If you + hold down the Alt key, the same combinations will work the same way, + but instead of scrolling within Eterm, they'll scroll the application + in the terminal (by sending PgUp/PgDn and up/down arrows). This works + in less, bash, and any other application which groks those keys. + + I also added a --without-mousewheel option to configure that will turn + off the default scrollwheel bindings. Of course, you can always use + action bindings in the config file to bind/rebind these any way you + like. + + While I was at it, I found and fixed a bug in the handling of the + Alt and Meta keys. + + I added a scroll() function to the script stuff which allows you to + bind keys/buttons to scroll up and down. While I was at it, I added + comments to script.c for each function you can use. + + And finally, the config file parser was moved to libast. + +------------------------------------------------------------------------------- diff --git a/acconfig.h b/acconfig.h index dbc750d..4fe60c9 100644 --- a/acconfig.h +++ b/acconfig.h @@ -361,6 +361,7 @@ #undef UTMP_IDENT #undef WINDOWS_IDENT #undef HAVE_SAVED_UIDS +#undef MOUSEWHEEL /* Leave that blank line there!! Autoheader needs it. diff --git a/bg/Makefile.am b/bg/Makefile.am index c28d87d..e7b5927 100644 --- a/bg/Makefile.am +++ b/bg/Makefile.am @@ -2,7 +2,7 @@ DIRS = tile scale EXTRA_DIST = tile/014.jpg tile/circuit.jpg tile/giger1.jpg tile/40.jpg tile/blackstone.jpg \ - tile/nebula.jpg scale/fourthday.jpg scale/gaia.jpg scale/galleon.jpg scale/Dragon.jpg \ + tile/nebula.jpg scale/Dragon.jpg \ README.backgrounds pixmapdir = $(pkgdatadir)/pix themedir = $(pkgdatadir)/themes diff --git a/bg/scale/fourthday.jpg b/bg/scale/fourthday.jpg deleted file mode 100644 index d0434fe..0000000 Binary files a/bg/scale/fourthday.jpg and /dev/null differ diff --git a/bg/scale/gaia.jpg b/bg/scale/gaia.jpg deleted file mode 100644 index 107f199..0000000 Binary files a/bg/scale/gaia.jpg and /dev/null differ diff --git a/bg/scale/galleon.jpg b/bg/scale/galleon.jpg deleted file mode 100644 index be599c9..0000000 Binary files a/bg/scale/galleon.jpg and /dev/null differ diff --git a/configure.in b/configure.in index 5545863..2049a79 100644 --- a/configure.in +++ b/configure.in @@ -571,6 +571,17 @@ AC_ARG_WITH(end, AC_MSG_RESULT(default vt102) fi, AC_MSG_RESULT(default) ) +AC_MSG_CHECKING(if mousewheel support should be enabled) +AC_ARG_WITH(mousewheel, +[ --without-mousewheel disable built-in mousewheel support], + if test "$withval" = "no"; then + AC_MSG_RESULT(no) + else + AC_MSG_RESULT(yes) + AC_DEFINE(MOUSEWHEEL) + fi, AC_MSG_RESULT(yes) + AC_DEFINE(MOUSEWHEEL) +) MULTICHAR_ENCODING="" AC_MSG_CHECKING(for multi-charset support) AC_ARG_ENABLE(multi-charset, diff --git a/src/actions.c b/src/actions.c index aca6d46..d914184 100644 --- a/src/actions.c +++ b/src/actions.c @@ -96,71 +96,117 @@ action_find_match(unsigned short mod, unsigned char button, KeySym keysym) return NULL; } +unsigned char +action_check_button(unsigned char button, int x_button) +{ + /* The event we're looking at is a button press. Make sure the + current action is also, and that it matches. Continue if not. */ + D_ACTIONS(("Checking button %d vs x_button %d\n", button, x_button)); + if (button == BUTTON_NONE) { + /* It was a button press, and this action is not a button action. */ + return FALSE; + } + if ((button != BUTTON_ANY) && (button != x_button)) { + /* It's a specific button, and the two don't match. */ + return FALSE; + } + D_ACTIONS(("Button match confirmed.\n")); + return TRUE; +} + +unsigned char +action_check_keysym(KeySym keysym, KeySym x_keysym) +{ + /* The event we're looking at is a key press. Make sure the + current action is also, and that it matches. Continue if not. */ + D_ACTIONS(("Checking keysym 0x%08x vs x_keysym 0x%08x\n", keysym, x_keysym)); + if (keysym == None) { + return FALSE; + } else if (keysym != x_keysym) { + return FALSE; + } + D_ACTIONS(("Keysym match confirmed.\n")); + return TRUE; +} + +unsigned char +action_check_modifiers(unsigned short mod, int x_mod) +{ + unsigned int m = (AltMask | MetaMask | NumLockMask); + + /* When we do have to check the modifiers, we do so in this order to eliminate the + most popular choices first. If any test fails, we return FALSE. */ + D_ACTIONS(("Checking modifier set 0x%08x (" MOD_FMT ") vs. X modifier set 0x%08x (" MOD_FMT ")\n", + mod, SHOW_MODS(mod), x_mod, SHOW_X_MODS(x_mod))); + if (mod != MOD_ANY) { + /* LOGICAL_XOR() returns true if either the first parameter or the second parameter + is true, but not both...just like XOR. If the mask we're looking for is set in + mod but not in x_mod, or set in x_mod but not in mod, we don't have a match. */ + if (LOGICAL_XOR((mod & MOD_CTRL), (x_mod & ControlMask))) { + return FALSE; + } + if (LOGICAL_XOR((mod & MOD_SHIFT), (x_mod & ShiftMask))) { + return FALSE; + } + if (MetaMask != AltMask) { + if (LOGICAL_XOR((mod & MOD_ALT), (x_mod & AltMask))) { + return FALSE; + } + if (LOGICAL_XOR((mod & MOD_META), (x_mod & MetaMask))) { + return FALSE; + } + } else { + if (LOGICAL_XOR((mod & (MOD_META | MOD_ALT)), (x_mod & (MetaMask | AltMask)))) { + return FALSE; + } + } + if (LOGICAL_XOR((mod & MOD_LOCK), (x_mod & LockMask))) { + return FALSE; + } + /* These tests can't use LOGICAL_XOR because the second test has an additional + restriction that the Mod?Mask cannot be set in m; i.e., we want to ignore + any Mod?Mask assigned to Alt, Meta, or the NumLock On state. */ + if (((mod & MOD_MOD1) && !(x_mod & Mod1Mask)) || (!(mod & MOD_MOD1) && (x_mod & Mod1Mask) && !(Mod1Mask & m))) { + return FALSE; + } + if (((mod & MOD_MOD2) && !(x_mod & Mod2Mask)) || (!(mod & MOD_MOD2) && (x_mod & Mod2Mask) && !(Mod2Mask & m))) { + return FALSE; + } + if (((mod & MOD_MOD3) && !(x_mod & Mod3Mask)) || (!(mod & MOD_MOD3) && (x_mod & Mod3Mask) && !(Mod3Mask & m))) { + return FALSE; + } + if (((mod & MOD_MOD4) && !(x_mod & Mod4Mask)) || (!(mod & MOD_MOD4) && (x_mod & Mod4Mask) && !(Mod4Mask & m))) { + return FALSE; + } + if (((mod & MOD_MOD5) && !(x_mod & Mod5Mask)) || (!(mod & MOD_MOD5) && (x_mod & Mod5Mask) && !(Mod5Mask & m))) { + return FALSE; + } + } + D_ACTIONS(("Modifier match confirmed.\n")); + return TRUE; +} + unsigned char action_dispatch(event_t *ev, KeySym keysym) { action_t *action; - unsigned int m = (AltMask | MetaMask | NumLockMask); ASSERT_RVAL(ev != NULL, 0); ASSERT_RVAL(ev->xany.type == ButtonPress || ev->xany.type == KeyPress, 0); - D_ACTIONS(("Event %8p: Button %d, Keysym 0x%08x, Key State 0x%08x\n", ev, ev->xbutton.button, keysym, ev->xkey.state)); + D_ACTIONS(("Event %8p: Button %d, Keysym 0x%08x, Key State 0x%08x (modifiers " MOD_FMT ")\n", + ev, ev->xbutton.button, keysym, ev->xkey.state, SHOW_X_MODS(ev->xkey.state))); for (action = action_list; action; action = action->next) { - D_ACTIONS(("Checking action. mod == 0x%08x, button == %d, keysym == 0x%08x\n", action->mod, action->button, action->keysym)); /* The very first thing we do is match the event type to the type of the current action. This means that we'll only run through the modifier checks below if we absolutely have to. */ - if (ev->xany.type == ButtonPress) { - /* The event we're looking at is a button press. Make sure the - current action is also, and that it matches. Continue if not. */ - if ((action->button == BUTTON_NONE) || ((action->button != BUTTON_ANY) && (action->button != ev->xbutton.button))) { - continue; - } - } else { - /* The event we're looking at is a key press. Make sure the - current action is also, and that it matches. Continue if not. */ - if (!(action->keysym) || (keysym != action->keysym)) { - continue; + if ((ev->xany.type == ButtonPress && action_check_button(action->button, ev->xbutton.button)) + || (ev->xany.type == KeyPress && action_check_keysym(action->keysym, action->keysym))) { + if (action_check_modifiers(action->mod, ev->xkey.state)) { + D_ACTIONS(("Match found.\n")); + /* If we've passed all the above tests, it's a match. Dispatch the handler. */ + return ((action->handler)(ev, action)); } } - D_ACTIONS(("Button/key passed.\n")); - if (action->mod != MOD_ANY) { - /* When we do have to check the modifiers, we do so in - this order to eliminate the most popular choices first. */ - if (LOGICAL_XOR((action->mod & MOD_CTRL), (ev->xkey.state & ControlMask))) { - continue; - } - if (LOGICAL_XOR((action->mod & MOD_SHIFT), (ev->xkey.state & ShiftMask))) { - continue; - } - if (LOGICAL_XOR((action->mod & MOD_ALT), (ev->xkey.state & AltMask))) { - continue; - } - if (LOGICAL_XOR((action->mod & MOD_META), (ev->xkey.state & MetaMask))) { - continue; - } - if (LOGICAL_XOR((action->mod & MOD_LOCK), (ev->xkey.state & LockMask))) { - continue; - } - if (((action->mod & MOD_MOD1) && !(ev->xkey.state & Mod1Mask)) || (!(action->mod & MOD_MOD1) && (ev->xkey.state & Mod1Mask) && !(Mod1Mask & m))) { - continue; - } - if (((action->mod & MOD_MOD2) && !(ev->xkey.state & Mod2Mask)) || (!(action->mod & MOD_MOD2) && (ev->xkey.state & Mod2Mask) && !(Mod2Mask & m))) { - continue; - } - if (((action->mod & MOD_MOD3) && !(ev->xkey.state & Mod3Mask)) || (!(action->mod & MOD_MOD3) && (ev->xkey.state & Mod3Mask) && !(Mod3Mask & m))) { - continue; - } - if (((action->mod & MOD_MOD4) && !(ev->xkey.state & Mod4Mask)) || (!(action->mod & MOD_MOD4) && (ev->xkey.state & Mod4Mask) && !(Mod4Mask & m))) { - continue; - } - if (((action->mod & MOD_MOD5) && !(ev->xkey.state & Mod5Mask)) || (!(action->mod & MOD_MOD5) && (ev->xkey.state & Mod5Mask) && !(Mod5Mask & m))) { - continue; - } - } - D_ACTIONS(("Match found.\n")); - /* If we've passed all the above tests, it's a match. Dispatch the handler. */ - return ((action->handler)(ev, action)); } return (0); } diff --git a/src/actions.h b/src/actions.h index 20e3da0..40cabe9 100644 --- a/src/actions.h +++ b/src/actions.h @@ -41,24 +41,28 @@ typedef enum { #define KEYSYM_NONE (0UL) -#define MOD_NONE (0UL) -#define MOD_CTRL (1UL << 0) -#define MOD_SHIFT (1UL << 1) -#define MOD_LOCK (1UL << 2) -#define MOD_META (1UL << 3) -#define MOD_ALT (1UL << 4) -#define MOD_MOD1 (1UL << 5) -#define MOD_MOD2 (1UL << 6) -#define MOD_MOD3 (1UL << 7) -#define MOD_MOD4 (1UL << 8) -#define MOD_MOD5 (1UL << 9) -#define MOD_ANY (1UL << 10) +#define MOD_NONE (0UL) +#define MOD_CTRL (1UL << 0) +#define MOD_SHIFT (1UL << 1) +#define MOD_LOCK (1UL << 2) +#define MOD_META (1UL << 3) +#define MOD_ALT (1UL << 4) +#define MOD_MOD1 (1UL << 5) +#define MOD_MOD2 (1UL << 6) +#define MOD_MOD3 (1UL << 7) +#define MOD_MOD4 (1UL << 8) +#define MOD_MOD5 (1UL << 9) +#define MOD_ANY (1UL << 10) -#define BUTTON_NONE (0) -#define BUTTON_ANY (0xff) +#define BUTTON_NONE (0) +#define BUTTON_ANY (0xff) #define LOGICAL_XOR(a, b) !(((a) && (b)) || (!(a) && !(b))) +#define SHOW_MODS(m) ((m & MOD_CTRL) ? 'C' : 'c'), ((m & MOD_SHIFT) ? 'S' : 's'), ((m & MOD_META) ? 'M' : 'm'), ((m & MOD_ALT) ? 'A' : 'a') +#define SHOW_X_MODS(m) ((m & ControlMask) ? 'C' : 'c'), ((m & ShiftMask) ? 'S' : 's'), ((m & MetaMask) ? 'M' : 'm'), ((m & AltMask) ? 'A' : 'a') +#define MOD_FMT "%c%c%c%c" + /************ Structures ************/ typedef struct action_struct action_t; typedef unsigned char (*action_handler_t) (event_t *, action_t *); @@ -87,6 +91,9 @@ extern unsigned char action_handle_echo(event_t *ev, action_t *action); extern unsigned char action_handle_script(event_t *ev, action_t *action); extern unsigned char action_handle_menu(event_t *ev, action_t *action); extern action_t *action_find_match(unsigned short mod, unsigned char button, KeySym keysym); +extern unsigned char action_check_button(unsigned char button, int x_button); +extern unsigned char action_check_keysym(KeySym keysym, KeySym x_keysym); +extern unsigned char action_check_modifiers(unsigned short mod, int x_mod); extern unsigned char action_dispatch(event_t *ev, KeySym keysym); extern void action_add(unsigned short mod, unsigned char button, KeySym keysym, action_type_t type, void *param); diff --git a/src/eterm_debug.h b/src/eterm_debug.h index c3b3b64..e820af5 100644 --- a/src/eterm_debug.h +++ b/src/eterm_debug.h @@ -80,7 +80,4 @@ # define DEBUG_X 9 -# define DEBUG_PARSE 9999 -# define D_PARSE(x) D_NEVER(x) - #endif /* _ETERM_DEBUG_H */ diff --git a/src/events.c b/src/events.c index c99f467..d01c2f2 100644 --- a/src/events.c +++ b/src/events.c @@ -640,24 +640,65 @@ handle_button_press(event_t *ev) } button_state.last_button_press = 3; break; +#ifdef MOUSEWHEEL + /* This section activates the following bindings: + * + * Mousewheel Up -- Scroll up 1 page + * Ctrl + Mousewheel Up -- Scroll up 5 pages + * Shift + Mousewheel Up -- Scroll up 1 line + * Alt + Mousewheel Up -- Send PgUp to tty + * Alt + Ctrl + Mousewheel Up -- Send 5 PgUp's to tty + * Alt + Shift + Mousewheel Up -- Send Up Arrow to tty + * + * Mousewheel Down -- Scroll down 1 page + * Ctrl + Mousewheel Down -- Scroll down 5 pages + * Shift + Mousewheel Down -- Scroll down 1 line + * Alt + Mousewheel Down -- Send PgDn to tty + * Alt + Ctrl + Mousewheel Down -- Send 5 PgDn's to tty + * Alt + Shift + Mousewheel Down -- Send Down Arrow to tty + * + * Note that the number of lines which constitute a "page" is equal to the number + * of text rows in the terminal window. The context lines are subtracted out *after* + * the conversion is done. In other words, scrolling 5 pages means scrolling + * (5 * LINES_PER_PAGE) - CONTEXT_LINES + * _not_ + * (LINES_PER_PAGE - CONTEXT_LINES) * 5 + * + * This is also true for the scroll() function in script.c. + */ case Button4: - if ((button_state.last_button_press == 4) && (ev->xbutton.time - button_state.button_press < MULTICLICK_TIME)) { - button_state.clicks++; - } else { - button_state.clicks = 1; + if (action_check_modifiers(MOD_CTRL, ev->xbutton.state)) { + scr_page(UP, (TermWin.nrow * 5) - CONTEXT_LINES); + } else if (action_check_modifiers(MOD_SHIFT, ev->xbutton.state)) { + scr_page(UP, 1); + } else if (action_check_modifiers(MOD_ALT, ev->xbutton.state)) { + tt_write("\033[5~", 4); + } else if (action_check_modifiers((MOD_ALT | MOD_SHIFT), ev->xbutton.state)) { + tt_write("\033[A", 3); + } else if (action_check_modifiers((MOD_ALT | MOD_CTRL), ev->xbutton.state)) { + tt_write("\033[5~\033[5~\033[5~\033[5~\033[5~", 20); + } else { + scr_page(UP, TermWin.nrow - CONTEXT_LINES); } button_state.last_button_press = 4; - scr_page(UP, ((ev->xbutton.state & ShiftMask) ? (1) : (TermWin.nrow - CONTEXT_LINES)) * ((button_state.clicks > 1) ? 3 : 1)); break; case Button5: - if ((button_state.last_button_press == 5) && (ev->xbutton.time - button_state.button_press < MULTICLICK_TIME)) { - button_state.clicks++; - } else { - button_state.clicks = 1; + if (action_check_modifiers(MOD_CTRL, ev->xbutton.state)) { + scr_page(DN, (TermWin.nrow * 5) - CONTEXT_LINES); + } else if (action_check_modifiers(MOD_SHIFT, ev->xbutton.state)) { + scr_page(DN, 1); + } else if (action_check_modifiers(MOD_ALT, ev->xbutton.state)) { + tt_write("\033[6~", 4); + } else if (action_check_modifiers((MOD_ALT | MOD_SHIFT), ev->xbutton.state)) { + tt_write("\033[B", 3); + } else if (action_check_modifiers((MOD_ALT | MOD_CTRL), ev->xbutton.state)) { + tt_write("\033[6~\033[6~\033[6~\033[6~\033[6~", 20); + } else { + scr_page(DN, TermWin.nrow - CONTEXT_LINES); } button_state.last_button_press = 5; - scr_page(DN, ((ev->xbutton.state & ShiftMask) ? (1) : (TermWin.nrow - CONTEXT_LINES)) * ((button_state.clicks > 1) ? 3 : 1)); break; +#endif default: break; } } diff --git a/src/options.c b/src/options.c index 881a86b..eb76f8b 100644 --- a/src/options.c +++ b/src/options.c @@ -68,24 +68,7 @@ static void *parse_menuitem(char *, void *); static void *parse_bbar(char *, void *); static void *parse_xim(char *, void *); static void *parse_multichar(char *, void *); -static conf_var_t *conf_new_var(void); -static void conf_free_var(conf_var_t *); -static char *conf_get_var(const char *); -static void conf_put_var(char *, char *); -static char *builtin_random(char *); -static char *builtin_exec(char *); -static char *builtin_get(char *); -static char *builtin_put(char *); -static char *builtin_dirscan(char *); -static char *builtin_version(char *); -static char *builtin_appname(char *); -static void *parse_null(char *, void *); -static ctx_t *context; -static ctx_state_t *ctx_state; -static eterm_func_t *builtins; -static unsigned char ctx_cnt, ctx_idx, ctx_state_idx, ctx_state_cnt, fstate_cnt, builtin_cnt, builtin_idx; -static conf_var_t *conf_vars = NULL; static char *rs_pipe_name = NULL; static int rs_shade = 0; static char *rs_tint = NULL; @@ -102,13 +85,6 @@ static char *rs_multichar_encoding = NULL; static char *rs_greek_keyboard = NULL; #endif -const char *true_vals[] = -{"1", "on", "true", "yes"}; -const char *false_vals[] = -{"0", "off", "false", "no"}; - -fstate_t *fstate; -unsigned char fstate_idx; unsigned long Options = (Opt_scrollbar), image_toggles = 0; char *theme_dir = NULL, *user_dir = NULL; char **rs_exec_args = NULL; /* Args to exec (-e or --exec) */ @@ -365,7 +341,7 @@ usage(void) unsigned short i, col; printf("Eterm Enlightened Terminal Emulator for the X Window System\n"); - printf("Copyright (c) 1997-2000, " AUTHORS "\n\n"); + printf("Copyright (c) 1997-2001, " AUTHORS "\n\n"); printf("Usage for " APL_NAME " " VERSION ":\n\n"); printf("%7s %17s %40s\n", "POSIX", "GNU", "Description"); printf("%8s %10s %41s\n", "=======", "===============================", @@ -405,7 +381,7 @@ version(void) { printf("Eterm " VERSION "\n"); - printf("Copyright (c) 1997-2000, " AUTHORS "\n\n"); + printf("Copyright (c) 1997-2001, " AUTHORS "\n\n"); printf("Build info:\n"); printf(" Built on " BUILD_DATE "\n"); @@ -1178,652 +1154,6 @@ get_initial_options(int argc, char *argv[]) } /* End main for loop */ } -/***** The Config File Section *****/ -/* This function must be called before any other conf_*() function. - Otherwise you will be bitten by dragons. That's life. */ -void -conf_init_subsystem(void) { - - /* Initialize the context list and establish a catch-all "null" context */ - ctx_cnt = 20; - ctx_idx = 0; - context = (ctx_t *) MALLOC(sizeof(ctx_t) * ctx_cnt); - MEMSET(context, 0, sizeof(ctx_t) * ctx_cnt); - context[0].name = STRDUP("null"); - context[0].handler = parse_null; - - /* Initialize the context state stack and set the current context to "null" */ - ctx_state_cnt = 20; - ctx_state_idx = 0; - ctx_state = (ctx_state_t *) MALLOC(sizeof(ctx_state_t) * ctx_state_cnt); - MEMSET(ctx_state, 0, sizeof(ctx_state_t) * ctx_state_cnt); - - /* Initialize the file state stack */ - fstate_cnt = 10; - fstate_idx = 0; - fstate = (fstate_t *) MALLOC(sizeof(fstate_t) * fstate_cnt); - MEMSET(fstate, 0, sizeof(fstate_t) * fstate_cnt); - - /* Initialize the builtin function table */ - builtin_cnt = 10; - builtin_idx = 0; - builtins = (eterm_func_t *) MALLOC(sizeof(eterm_func_t) * builtin_cnt); - MEMSET(builtins, 0, sizeof(eterm_func_t) * builtin_cnt); - - /* Register the omni-present builtin functions */ - conf_register_builtin("appname", builtin_appname); - conf_register_builtin("version", builtin_version); - conf_register_builtin("exec", builtin_exec); - conf_register_builtin("random", builtin_random); - conf_register_builtin("get", builtin_get); - conf_register_builtin("put", builtin_put); - conf_register_builtin("dirscan", builtin_dirscan); - - /* For expediency, Eterm registers its contexts here. If you want to use - this parser in another program, remove these lines. */ - conf_register_context("color", parse_color); - conf_register_context("attributes", parse_attributes); - conf_register_context("toggles", parse_toggles); - conf_register_context("keyboard", parse_keyboard); - conf_register_context("misc", parse_misc); - conf_register_context("imageclasses", parse_imageclasses); - conf_register_context("image", parse_image); - conf_register_context("actions", parse_actions); - conf_register_context("menu", parse_menu); - conf_register_context("menuitem", parse_menuitem); - conf_register_context("button_bar", parse_bbar); - conf_register_context("xim", parse_xim); - conf_register_context("multichar", parse_multichar); -} - -/* Register a new config file context */ -unsigned char -conf_register_context(char *name, ctx_handler_t handler) { - - if (++ctx_idx == ctx_cnt) { - ctx_cnt *= 2; - context = (ctx_t *) REALLOC(context, sizeof(ctx_t) * ctx_cnt); - } - context[ctx_idx].name = STRDUP(name); - context[ctx_idx].handler = handler; - D_OPTIONS(("Added context \"%s\" with ID %d and handler 0x%08x\n", context[ctx_idx].name, ctx_idx, context[ctx_idx].handler)); - return (ctx_idx); -} - -/* Register a new file state structure */ -unsigned char -conf_register_fstate(FILE *fp, char *path, char *outfile, unsigned long line, unsigned char flags) { - - if (++fstate_idx == fstate_cnt) { - fstate_cnt *= 2; - fstate = (fstate_t *) REALLOC(fstate, sizeof(fstate_t) * fstate_cnt); - } - fstate[fstate_idx].fp = fp; - fstate[fstate_idx].path = path; - fstate[fstate_idx].outfile = outfile; - fstate[fstate_idx].line = line; - fstate[fstate_idx].flags = flags; - return (fstate_idx); -} - -/* Register a new builtin function */ -unsigned char -conf_register_builtin(char *name, eterm_func_ptr_t ptr) { - - builtins[builtin_idx].name = STRDUP(name); - builtins[builtin_idx].ptr = ptr; - if (++builtin_idx == builtin_cnt) { - builtin_cnt *= 2; - builtins = (eterm_func_t *) REALLOC(builtins, sizeof(eterm_func_t) * builtin_cnt); - } - return (builtin_idx - 1); -} - -/* Register a new config file context */ -unsigned char -conf_register_context_state(unsigned char ctx_id) { - - if (++ctx_state_idx == ctx_state_cnt) { - ctx_state_cnt *= 2; - ctx_state = (ctx_state_t *) REALLOC(ctx_state, sizeof(ctx_state_t) * ctx_state_cnt); - } - ctx_state[ctx_state_idx].ctx_id = ctx_id; - ctx_state[ctx_state_idx].state = NULL; - return (ctx_state_idx); -} - -void -conf_free_subsystem(void) -{ - conf_var_t *v, *tmp; - unsigned long i; - - for (v = conf_vars; v;) { - tmp = v; - v = v->next; - conf_free_var(tmp); - } - for (i = 0; i < builtin_idx; i++) { - FREE(builtins[i].name); - } - for (i = 0; i <= ctx_idx; i++) { - FREE(context[i].name); - } - FREE(ctx_state); - FREE(builtins); - FREE(fstate); - FREE(context); -} - -static conf_var_t * -conf_new_var(void) -{ - conf_var_t *v; - - v = (conf_var_t *) MALLOC(sizeof(conf_var_t)); - MEMSET(v, 0, sizeof(conf_var_t)); - return v; -} - -static void -conf_free_var(conf_var_t *v) -{ - if (v->var) { - FREE(v->var); - } - if (v->value) { - FREE(v->value); - } - FREE(v); -} - -static char * -conf_get_var(const char *var) -{ - conf_var_t *v; - - D_OPTIONS(("var == \"%s\"\n", var)); - for (v = conf_vars; v; v = v->next) { - if (!strcmp(v->var, var)) { - D_OPTIONS(("Found it at %8p: \"%s\" == \"%s\"\n", v, v->var, v->value)); - return (v->value); - } - } - D_OPTIONS(("Not found.\n")); - return NULL; -} - -static void -conf_put_var(char *var, char *val) -{ - conf_var_t *v, *loc = NULL, *tmp; - - ASSERT(var != NULL); - D_OPTIONS(("var == \"%s\", val == \"%s\"\n", var, val)); - - for (v = conf_vars; v; loc = v, v = v->next) { - int n; - - n = strcmp(var, v->var); - D_OPTIONS(("Comparing at %8p: \"%s\" -> \"%s\", n == %d\n", v, v->var, v->value, n)); - if (n == 0) { - FREE(v->value); - if (val) { - v->value = val; - D_OPTIONS(("Variable already defined. Replacing its value with \"%s\"\n", v->value)); - } else { - D_OPTIONS(("Variable already defined. Deleting it.\n")); - if (loc) { - loc->next = v->next; - } else { - conf_vars = v->next; - } - conf_free_var(v); - } - return; - } else if (n < 0) { - break; - } - } - if (!val) { - D_OPTIONS(("Empty value given for non-existant variable \"%s\". Aborting.\n", var)); - return; - } - D_OPTIONS(("Inserting new var/val pair between \"%s\" and \"%s\"\n", ((loc) ? loc->var : "-beginning-"), ((v) ? v->var : "-end-"))); - tmp = conf_new_var(); - if (loc == NULL) { - tmp->next = conf_vars; - conf_vars = tmp; - } else { - tmp->next = loc->next; - loc->next = tmp; - } - tmp->var = var; - tmp->value = val; -} - -static char * -builtin_random(char *param) -{ - - unsigned long n, index; - static unsigned int rseed = 0; - - D_PARSE(("builtin_random(%s) called\n", param)); - - if (rseed == 0) { - rseed = (unsigned int) (getpid() * time(NULL) % ((unsigned int) -1)); - srand(rseed); - } - n = num_words(param); - index = (int) (n * ((float) rand()) / (RAND_MAX + 1.0)) + 1; - D_PARSE(("random index == %lu\n", index)); - - return (get_word(index, param)); -} - -static char * -builtin_exec(char *param) -{ - unsigned long fsize; - char *Command, *Output = NULL; - char OutFile[256]; - FILE *fp; - int fd; - - D_PARSE(("builtin_exec(%s) called\n", param)); - - Command = (char *) MALLOC(CONFIG_BUFF); - strcpy(OutFile, "Eterm-exec-"); - fd = libast_temp_file(OutFile, sizeof(OutFile)); - if ((fd < 0) || fchown(fd, my_ruid, my_rgid)) { - print_error("Unable to create unique temporary file for \"%s\" -- %s\n", param, strerror(errno)); - return ((char *) NULL); - } - if (strlen(param) + strlen(OutFile) + 8 > CONFIG_BUFF) { - print_error("Parse error in file %s, line %lu: Cannot execute command, line too long\n", - file_peek_path(), file_peek_line()); - return ((char *) NULL); - } - strcpy(Command, param); - strcat(Command, " >"); - strcat(Command, OutFile); - system(Command); - if ((fp = fdopen(fd, "rb")) != NULL) { - fseek(fp, 0, SEEK_END); - fsize = ftell(fp); - rewind(fp); - if (fsize) { - Output = (char *) MALLOC(fsize + 1); - fread(Output, fsize, 1, fp); - Output[fsize] = 0; - fclose(fp); - remove(OutFile); - Output = condense_whitespace(Output); - } else { - print_warning("Command at line %lu of file %s returned no output.\n", file_peek_line(), file_peek_path()); - } - } else { - print_warning("Output file %s could not be created. (line %lu of file %s)\n", NONULL(OutFile), - file_peek_line(), file_peek_path()); - } - FREE(Command); - - return (Output); -} - -static char * -builtin_get(char *param) -{ - char *s, *f, *v; - unsigned short n; - - if (!param || ((n = num_words(param)) > 2)) { - print_error("Parse error in file %s, line %lu: Invalid syntax for %get(). Syntax is: %get(variable)\n", file_peek_path(), file_peek_line()); - return NULL; - } - - D_PARSE(("builtin_get(%s) called\n", param)); - s = get_word(1, param); - if (n == 2) { - f = get_word(2, param); - } else { - f = NULL; - } - v = conf_get_var(s); - FREE(s); - if (v) { - if (f) { - FREE(f); - } - return (STRDUP(v)); - } else if (f) { - return f; - } else { - return NULL; - } -} - -static char * -builtin_put(char *param) -{ - char *var, *val; - - if (!param || (num_words(param) != 2)) { - print_error("Parse error in file %s, line %lu: Invalid syntax for %put(). Syntax is: %put(variable value)\n", file_peek_path(), file_peek_line()); - return NULL; - } - - D_PARSE(("builtin_put(%s) called\n", param)); - var = get_word(1, param); - val = get_word(2, param); - conf_put_var(var, val); - return NULL; -} - -static char * -builtin_dirscan(char *param) -{ - int i; - unsigned long n; - DIR *dirp; - struct dirent *dp; - struct stat filestat; - char *dir, *buff; - - if (!param || (num_words(param) != 1)) { - print_error("Parse error in file %s, line %lu: Invalid syntax for %dirscan(). Syntax is: %dirscan(directory)\n", file_peek_path(), file_peek_line()); - return NULL; - } - D_PARSE(("builtin_dirscan(%s)\n", param)); - dir = get_word(1, param); - dirp = opendir(dir); - if (!dirp) { - return NULL; - } - buff = (char *) MALLOC(CONFIG_BUFF); - *buff = 0; - n = CONFIG_BUFF; - - for (i = 0; (dp = readdir(dirp)) != NULL;) { - char fullname[PATH_MAX]; - - snprintf(fullname, sizeof(fullname), "%s/%s", dir, dp->d_name); - if (stat(fullname, &filestat)) { - D_PARSE((" -> Couldn't stat() file %s -- %s\n", fullname, strerror(errno))); - } else { - if (S_ISREG(filestat.st_mode)) { - unsigned long len; - - len = strlen(dp->d_name); - if (len < n) { - strcat(buff, dp->d_name); - strcat(buff, " "); - n -= len + 1; - } - } - } - if (n < 2) { - break; - } - } - closedir(dirp); - return buff; -} - -static char * -builtin_version(char *param) -{ - - if (param) { - D_PARSE(("builtin_version(%s) called\n", param)); - } - - return (STRDUP(VERSION)); -} - -static char * -builtin_appname(char *param) -{ - - if (param) { - D_PARSE(("builtin_appname(%s) called\n", param)); - } - - return (STRDUP(APL_NAME "-" VERSION)); -} - -/* shell_expand() takes care of shell variable expansion, quote conventions, - calling of built-in functions, etc. -- mej */ -char * -shell_expand(char *s) -{ - - register char *tmp; - register char *pbuff = s, *tmp1; - register unsigned long j, k, l = 0; - char new[CONFIG_BUFF]; - unsigned char in_single = 0, in_double = 0; - unsigned long cnt1 = 0, cnt2 = 0; - const unsigned long max = CONFIG_BUFF - 1; - char *Command, *Output, *EnvVar; - - ASSERT_RVAL(s != NULL, (char *) NULL); - -#if 0 - new = (char *) MALLOC(CONFIG_BUFF); -#endif - - for (j = 0; *pbuff && j < max; pbuff++, j++) { - switch (*pbuff) { - case '~': - D_OPTIONS(("Tilde detected.\n")); - if (!in_single && !in_double) { - strncpy(new + j, getenv("HOME"), max - j); - cnt1 = strlen(getenv("HOME")) - 1; - cnt2 = max - j - 1; - j += MIN(cnt1, cnt2); - } else { - new[j] = *pbuff; - } - break; - case '\\': - D_OPTIONS(("Escape sequence detected.\n")); - if (!in_single || (in_single && *(pbuff + 1) == '\'')) { - switch (tolower(*(++pbuff))) { - case 'n': - new[j] = '\n'; - break; - case 'r': - new[j] = '\r'; - break; - case 't': - new[j] = '\t'; - break; - case 'b': - new[j] = '\b'; - break; - case 'f': - new[j] = '\f'; - break; - case 'a': - new[j] = '\a'; - break; - case 'v': - new[j] = '\v'; - break; - case 'e': - new[j] = '\033'; - break; - default: - new[j] = *pbuff; - break; - } - } else { - new[j++] = *(pbuff++); - new[j] = *pbuff; - } - break; - case '%': - D_OPTIONS(("%% detected.\n")); - for (k = 0, pbuff++; builtins[k].name != NULL; k++) { - D_PARSE(("Checking for function %%%s, pbuff == \"%s\"\n", builtins[k].name, pbuff)); - l = strlen(builtins[k].name); - if (!strncasecmp(builtins[k].name, pbuff, l) && - ((pbuff[l] == '(') || (pbuff[l] == ' ' && pbuff[l + 1] == ')'))) { - break; - } - } - if (builtins[k].name == NULL) { - new[j] = *pbuff; - } else { - D_OPTIONS(("Call to built-in function %s detected.\n", builtins[k].name)); - Command = (char *) MALLOC(CONFIG_BUFF); - pbuff += l; - if (*pbuff != '(') - pbuff++; - for (tmp1 = Command, pbuff++, l = 1; l && *pbuff; pbuff++, tmp1++) { - switch (*pbuff) { - case '(': - l++; - *tmp1 = *pbuff; - break; - case ')': - l--; - default: - *tmp1 = *pbuff; - break; - } - } - *(--tmp1) = 0; - if (l) { - print_error("parse error in file %s, line %lu: Mismatched parentheses\n", - file_peek_path(), file_peek_line()); - return ((char *) NULL); - } - Command = shell_expand(Command); - Output = (builtins[k].ptr) (Command); - FREE(Command); - if (Output) { - if (*Output) { - l = strlen(Output) - 1; - strncpy(new + j, Output, max - j); - cnt2 = max - j - 1; - j += MIN(l, cnt2); - } else { - j--; - } - FREE(Output); - } else { - j--; - } - pbuff--; - } - break; - case '`': -#ifdef ALLOW_BACKQUOTE_EXEC - D_OPTIONS(("Backquotes detected. Evaluating expression.\n")); - if (!in_single) { - Command = (char *) MALLOC(CONFIG_BUFF); - l = 0; - for (pbuff++; *pbuff && *pbuff != '`' && l < max; pbuff++, l++) { - Command[l] = *pbuff; - } - ASSERT(l < CONFIG_BUFF); - Command[l] = 0; - Command = shell_expand(Command); - Output = builtin_exec(Command); - FREE(Command); - if (Output) { - if (*Output) { - l = strlen(Output) - 1; - strncpy(new + j, Output, max - j); - cnt2 = max - j - 1; - j += MIN(l, cnt2); - } else { - j--; - } - FREE(Output); - } else { - j--; - } - } else { - new[j] = *pbuff; - } -#else - print_warning("Backquote execution support not compiled in, ignoring\n"); - new[j] = *pbuff; -#endif - break; - case '$': - D_OPTIONS(("Environment variable detected. Evaluating.\n")); - if (!in_single) { - EnvVar = (char *) MALLOC(128); - switch (*(++pbuff)) { - case '{': - for (pbuff++, k = 0; *pbuff != '}' && k < 127; k++, pbuff++) - EnvVar[k] = *pbuff; - break; - case '(': - for (pbuff++, k = 0; *pbuff != ')' && k < 127; k++, pbuff++) - EnvVar[k] = *pbuff; - break; - default: - for (k = 0; (isalnum(*pbuff) || *pbuff == '_') && k < 127; k++, pbuff++) - EnvVar[k] = *pbuff; - break; - } - EnvVar[k] = 0; - if ((tmp = getenv(EnvVar))) { - strncpy(new, tmp, max - j); - cnt1 = strlen(tmp) - 1; - cnt2 = max - j - 1; - j += MIN(cnt1, cnt2); - } - pbuff--; - } else { - new[j] = *pbuff; - } - break; - case '\"': - D_OPTIONS(("Double quotes detected.\n")); - if (!in_single) { - if (in_double) { - in_double = 0; - } else { - in_double = 1; - } - } - new[j] = *pbuff; - break; - - case '\'': - D_OPTIONS(("Single quotes detected.\n")); - if (in_single) { - in_single = 0; - } else { - in_single = 1; - } - new[j] = *pbuff; - break; - - default: - new[j] = *pbuff; - } - } - ASSERT(j < CONFIG_BUFF); - new[j] = 0; - - D_PARSE(("shell_expand(%s) returning \"%s\"\n", s, new)); - D_PARSE((" strlen(s) == %lu, strlen(new) == %lu, j == %lu\n", strlen(s), strlen(new), j)); - - strcpy(s, new); -#if 0 - FREE(new); -#endif - return (s); -} - /* The config file parsers. Each function handles a given context. */ static void * parse_color(char *buff, void *state) @@ -3010,7 +2340,8 @@ parse_actions(char *buff, void *state) action_add(mod, button, keysym, ACTION_SCRIPT, (void *) str); FREE(str); } else { - print_error("Parse error in file %s, line %lu: Syntax error (\"to\" not found)\n", file_peek_path(), file_peek_line()); + print_error("Parse error in file %s, line %lu: No valid action type found. Valid types are \"string,\" \"echo,\" \"menu,\" and \"script.\"\n", + file_peek_path(), file_peek_line()); return NULL; } @@ -3345,253 +2676,6 @@ parse_multichar(char *buff, void *state) buff = NULL; } -/* The config file reader. This looks for the config file by searching CONFIG_SEARCH_PATH. - If it can't find a config file, it displays a warning but continues. -- mej */ - -char * -conf_find_file(const char *file, const char *dir, const char *pathlist) { - - static char name[PATH_MAX], full_path[PATH_MAX]; - const char *path; - char *p; - short maxpathlen; - unsigned short len; - struct stat fst; - - REQUIRE_RVAL(file != NULL, NULL); - - getcwd(name, PATH_MAX); - D_OPTIONS(("conf_find_file(\"%s\", \"%s\", \"%s\") called from directory \"%s\".\n", file, NONULL(dir), NONULL(pathlist), name)); - - if (dir) { - strcpy(name, dir); - strcat(name, "/"); - strcat(name, file); - } else { - strcpy(name, file); - } - len = strlen(name); - D_OPTIONS(("Checking for file \"%s\"\n", name)); - if ((!access(name, R_OK)) && (!stat(name, &fst)) && (!S_ISDIR(fst.st_mode))) { - D_OPTIONS(("Found \"%s\"\n", name)); - return ((char *) name); - } - - /* maxpathlen is the longest possible path we can stuff into name[]. The - 2 saves room for - an additional / and the trailing null. */ - if ((maxpathlen = sizeof(name) - len - 2) <= 0) { - D_OPTIONS(("Too big. I lose. :(\n", name)); - return ((char *) NULL); - } - - for (path = pathlist; path != NULL && *path != '\0'; path = p) { - short n; - - /* Calculate the length of the next directory in the path */ - if ((p = strchr(path, ':')) != NULL) { - n = p++ - path; - } else { - n = strlen(path); - } - - /* Don't try if it's too long */ - if (n > 0 && n <= maxpathlen) { - /* Compose the /path/file combo */ - strncpy(full_path, path, n); - if (full_path[n - 1] != '/') { - full_path[n++] = '/'; - } - full_path[n] = '\0'; - strcat(full_path, name); - - D_OPTIONS(("Checking for file \"%s\"\n", full_path)); - if ((!access(full_path, R_OK)) && (!stat(full_path, &fst)) && (!S_ISDIR(fst.st_mode))) { - D_OPTIONS(("Found \"%s\"\n", full_path)); - return ((char *) full_path); - } - } - } - D_OPTIONS(("conf_find_file(): File \"%s\" not found in path.\n", name)); - return ((char *) NULL); -} - -FILE * -open_config_file(char *name) -{ - - FILE *fp; - int ver; - char buff[256], *begin_ptr, *end_ptr; - - ASSERT(name != NULL); - - fp = fopen(name, "rt"); - if (fp != NULL) { - fgets(buff, 256, fp); - if (BEG_STRCASECMP(buff, "<" PACKAGE "-")) { - print_warning("%s exists but does not contain the proper magic string (<" PACKAGE "-" VERSION ">)\n", name); - fclose(fp); - fp = NULL; - } else { - begin_ptr = strchr(buff, '-') + 1; - if ((end_ptr = strchr(buff, '>')) != NULL) { - *end_ptr = 0; - } - if ((ver = BEG_STRCASECMP(begin_ptr, VERSION)) > 0) { - print_warning("Config file is designed for a newer version of \n" PACKAGE); - } - } - } - return (fp); -} - -char * -conf_parse(char *conf_name, const char *dir, const char *path) { - - FILE *fp; - char *name = NULL, *outfile, *p = "."; - char buff[CONFIG_BUFF], orig_dir[PATH_MAX]; - register unsigned long i = 0; - unsigned char id = 0; - void *state = NULL; - - REQUIRE_RVAL(conf_name != NULL, 0); - - *orig_dir = 0; - if (path) { - if ((name = conf_find_file(conf_name, dir, path)) != NULL) { - if ((p = strrchr(name, '/')) != NULL) { - getcwd(orig_dir, PATH_MAX); - *p = 0; - p = name; - chdir(name); - } else { - p = "."; - } - } else { - return NULL; - } - } - if ((fp = open_config_file(conf_name)) == NULL) { - return NULL; - } - file_push(fp, conf_name, NULL, 1, 0); /* Line count starts at 1 because open_config_file() parses the first line */ - - for (; fstate_idx > 0;) { - for (; fgets(buff, CONFIG_BUFF, file_peek_fp());) { - file_inc_line(); - if (!strchr(buff, '\n')) { - print_error("Parse error in file %s, line %lu: line too long\n", file_peek_path(), file_peek_line()); - for (; fgets(buff, CONFIG_BUFF, file_peek_fp()) && !strrchr(buff, '\n');); - continue; - } - if (!(*buff) || *buff == '\n') { - continue; - } - chomp(buff); - switch (*buff) { - case '#': - case '<': - break; - case '%': - D_OPTIONS(("read_config(): Parsing line #%lu of file %s\n", file_peek_line(), file_peek_path())); - if (!BEG_STRCASECMP(get_pword(1, buff + 1), "include ")) { - char *path; - FILE *fp; - - shell_expand(buff); - path = get_word(2, buff + 1); - if ((fp = open_config_file(path)) == NULL) { - print_error("Error in file %s, line %lu: Unable to locate %%included config file %s (%s), continuing\n", file_peek_path(), file_peek_line(), - path, strerror(errno)); - } else { - file_push(fp, path, NULL, 1, 0); - } - } else if (!BEG_STRCASECMP(get_pword(1, buff + 1), "preproc ")) { - char cmd[PATH_MAX], fname[PATH_MAX]; - int fd; - FILE *fp; - - if (file_peek_preproc()) { - continue; - } - strcpy(fname, "Eterm-preproc-"); - fd = libast_temp_file(fname, PATH_MAX); - outfile = STRDUP(fname); - snprintf(cmd, PATH_MAX, "%s < %s > %s", get_pword(2, buff), file_peek_path(), fname); - system(cmd); - fp = fdopen(fd, "rt"); - if (fp != NULL) { - fclose(file_peek_fp()); - file_poke_fp(fp); - file_poke_preproc(1); - file_poke_outfile(outfile); - } - } else { - D_OPTIONS(("read_config(): Parsing line #%lu of file %s\n", file_peek_line(), file_peek_path())); - if (file_peek_skip()) { - continue; - } - shell_expand(buff); - } - break; - case 'b': - D_OPTIONS(("read_config(): Parsing line #%lu of file %s\n", file_peek_line(), file_peek_path())); - if (file_peek_skip()) { - continue; - } - if (!BEG_STRCASECMP(buff, "begin ")) { - name = get_pword(2, buff); - ctx_name_to_id(id, name, i); - ctx_push(id); - *buff = CONF_BEGIN_CHAR; - state = (*ctx_id_to_func(id))(buff, ctx_peek_last_state()); - ctx_poke_state(state); - break; - } - /* Intentional pass-through */ - case 'e': - if (*buff != 'b') { - D_OPTIONS(("read_config(): Parsing line #%lu of file %s\n", file_peek_line(), file_peek_path())); - } - if (!BEG_STRCASECMP(buff, "end ") || !strcasecmp(buff, "end")) { - if (ctx_get_depth()) { - *buff = CONF_END_CHAR; - state = (*ctx_id_to_func(id))(buff, ctx_peek_state()); - ctx_poke_state(NULL); - ctx_pop(); - id = ctx_peek_id(); - ctx_poke_state(state); - file_poke_skip(0); - } - break; - } - /* Intentional pass-through */ - default: - if (*buff != 'b' && *buff != 'e') { - D_OPTIONS(("read_config(): Parsing line #%lu of file %s\n", file_peek_line(), file_peek_path())); - } - if (file_peek_skip()) { - continue; - } - shell_expand(buff); - ctx_poke_state((*ctx_id_to_func(id))(buff, ctx_peek_state())); - } - } - fclose(file_peek_fp()); - if (file_peek_preproc()) { - remove(file_peek_outfile()); - FREE(file_peek_outfile()); - } - file_pop(); - } - if (*orig_dir) { - chdir(orig_dir); - } - D_OPTIONS(("Returning \"%s\"\n", p)); - return (STRDUP(p)); -} - char * conf_parse_theme(char **theme, char *conf_name, unsigned char fallback) { @@ -3628,19 +2712,6 @@ conf_parse_theme(char **theme, char *conf_name, unsigned char fallback) return NULL; } -static void * -parse_null(char *buff, void *state) { - - if (*buff == CONF_BEGIN_CHAR) { - return (NULL); - } else if (*buff == CONF_END_CHAR) { - return (NULL); - } else { - print_error("Parse error in file %s, line %lu: Not allowed in \"null\" context: \"%s\"\n", file_peek_path(), file_peek_line(), buff); - return (state); - } -} - /* Initialize the default values for everything */ void init_defaults(void) @@ -3686,6 +2757,24 @@ init_defaults(void) rs_multichar_encoding = STRDUP(MULTICHAR_ENCODING); #endif TermWin.internalBorder = DEFAULT_BORDER_WIDTH; + + /* Initialize the parser */ + conf_init_subsystem(); + + /* Register Eterm's context parsers. */ + conf_register_context("color", parse_color); + conf_register_context("attributes", parse_attributes); + conf_register_context("toggles", parse_toggles); + conf_register_context("keyboard", parse_keyboard); + conf_register_context("misc", parse_misc); + conf_register_context("imageclasses", parse_imageclasses); + conf_register_context("image", parse_image); + conf_register_context("actions", parse_actions); + conf_register_context("menu", parse_menu); + conf_register_context("menuitem", parse_menuitem); + conf_register_context("button_bar", parse_bbar); + conf_register_context("xim", parse_xim); + conf_register_context("multichar", parse_multichar); } /* Sync up options with our internal data after parsing options and configs */ diff --git a/src/options.h b/src/options.h index 00cbd3b..101be79 100644 --- a/src/options.h +++ b/src/options.h @@ -28,21 +28,6 @@ #include /* Xlib, Xutil, Xresource, Xfuncproto */ /************ Macros and Definitions ************/ -#if defined(PATH_MAX) && (PATH_MAX < 255) -# undef PATH_MAX -#endif -#ifndef PATH_MAX -# define PATH_MAX 255 -#endif - -#define CONF_BEGIN_CHAR ((char) 1) -#define CONF_END_CHAR ((char) 2) - -#define PARSE_TRY_USER_THEME ((unsigned char) 0x01) -#define PARSE_TRY_DEFAULT_THEME ((unsigned char) 0x02) -#define PARSE_TRY_NO_THEME ((unsigned char) 0x04) -#define PARSE_TRY_ALL ((unsigned char) 0x07) - #define OPT_BOOLEAN 0x0001 #define OPT_INTEGER 0x0002 #define OPT_STRING 0x0004 @@ -92,10 +77,10 @@ # define SAVE_THEME_CONFIG ((unsigned char) 1) # define SAVE_USER_CONFIG ((unsigned char) 0) -#define BOOL_OPT_ISTRUE(s) (!strcasecmp((s), true_vals[0]) || !strcasecmp((s), true_vals[1]) \ - || !strcasecmp((s), true_vals[2]) || !strcasecmp((s), true_vals[3])) -#define BOOL_OPT_ISFALSE(s) (!strcasecmp((s), false_vals[0]) || !strcasecmp((s), false_vals[1]) \ - || !strcasecmp((s), false_vals[2]) || !strcasecmp((s), false_vals[3])) +#define PARSE_TRY_USER_THEME ((unsigned char) 0x01) +#define PARSE_TRY_DEFAULT_THEME ((unsigned char) 0x02) +#define PARSE_TRY_NO_THEME ((unsigned char) 0x04) +#define PARSE_TRY_ALL ((unsigned char) 0x07) /* This defines how many mistakes to allow before giving up and printing the usage -- mej */ @@ -109,54 +94,6 @@ } \ } while(0) -/* The context table */ -#define ctx_name_to_id(the_id, n, i) do { \ - for ((i)=0; (i) <= ctx_idx; (i)++) { \ - if (!strcasecmp((n), context[(i)].name)) { \ - (the_id) = (i); \ - break; \ - } \ - } \ - if ((i) > ctx_idx) (the_id) = 0; \ - } while (0) -#define ctx_id_to_name(id) (context[(id)].name) -#define ctx_id_to_func(id) (context[(id)].handler) - -/* The context state stack. This keeps track of the current context and each previous one. */ -#define ctx_push(ctx) conf_register_context_state(ctx) -#define ctx_pop() (ctx_state_idx--) -#define ctx_peek() (ctx_state[ctx_state_idx]) -#define ctx_peek_id() (ctx_state[ctx_state_idx].ctx_id) -#define ctx_peek_state() (ctx_state[ctx_state_idx].state) -#define ctx_peek_last_id() (ctx_state[(ctx_state_idx?ctx_state_idx-1:0)].ctx_id) -#define ctx_peek_last_state() (ctx_state[(ctx_state_idx?ctx_state_idx-1:0)].state) -#define ctx_poke_state(q) ((ctx_state[ctx_state_idx].state) = (q)) -#define ctx_get_depth() (ctx_state_idx) - -/* The file state stack */ -#define FILE_SKIP_TO_END (0x01) -#define FILE_PREPROC (0x02) -#define file_push(f, p, o, l, fl) conf_register_fstate(f, p, o, l, fl) -#define file_pop() (fstate_idx--) -#define file_peek() (fstate[fstate_idx]) -#define file_peek_fp() (fstate[fstate_idx].fp) -#define file_peek_path() (fstate[fstate_idx].path) -#define file_peek_outfile() (fstate[fstate_idx].outfile) -#define file_peek_line() (fstate[fstate_idx].line) -#define file_peek_skip() (fstate[fstate_idx].flags & FILE_SKIP_TO_END) -#define file_peek_preproc() (fstate[fstate_idx].flags & FILE_PREPROC) - -#define file_poke_fp(f) ((fstate[fstate_idx].fp) = (f)) -#define file_poke_path(p) ((fstate[fstate_idx].path) = (p)) -#define file_poke_outfile(o) ((fstate[fstate_idx].outfile) = (o)) -#define file_poke_line(l) ((fstate[fstate_idx].line) = (l)) -#define file_skip_to_end() ((fstate[fstate_idx].flags) |= (FILE_SKIP_TO_END)) -#define file_poke_skip(s) do {if (s) {fstate[fstate_idx].flags |= FILE_SKIP_TO_END;} else {fstate[fstate_idx].flags &= ~(FILE_SKIP_TO_END);} } while (0) -#define file_poke_preproc(s) do {if (s) {fstate[fstate_idx].flags |= FILE_PREPROC;} else {fstate[fstate_idx].flags &= ~(FILE_PREPROC);} } while (0) -#define file_poke(f, p, o, l, fl) do {file_poke_fp(f); file_poke_path(p); file_poke_outfile(o); file_poke_line(l); fstate[fstate_idx].flags = (fl);} while (0) - -#define file_inc_line() (fstate[fstate_idx].line++) - #define to_keysym(p,s) do { KeySym sym; \ if (s && ((sym = XStringToKeysym(s)) != 0)) *p = sym; \ } while (0) @@ -165,40 +102,8 @@ #define RESET_AND_ASSIGN(var, val) do {if ((var) != NULL) FREE(var); (var) = (val);} while (0) /************ Structures ************/ -/* Contexts */ -typedef void * (*ctx_handler_t)(char *, void *); -typedef struct context_struct { - char *name; - ctx_handler_t handler; -} ctx_t; -typedef struct ctx_state_struct { - unsigned char ctx_id; - void *state; -} ctx_state_t; - -/* Parser states */ -typedef struct file_state_struct { - FILE *fp; - char *path, *outfile; - unsigned long line; - unsigned char flags; -} fstate_t; - -/* Built-in functions */ -typedef char * (*eterm_func_ptr_t) (char *); -typedef struct eterm_func_struct { - char *name; - eterm_func_ptr_t ptr; -} eterm_func_t; - -typedef struct conf_var_struct { - char *var, *value; - struct conf_var_struct *next; -} conf_var_t; /************ Variables ************/ -extern fstate_t *fstate; -extern unsigned char fstate_idx; extern unsigned long Options, image_toggles; extern char *theme_dir, *user_dir; extern char **rs_exec_args; /* Args to exec (-e or --exec) */ @@ -255,16 +160,6 @@ _XFUNCPROTOBEGIN unsigned long num_words(const char *str); extern void get_initial_options(int, char **); extern void get_options(int, char **); -extern void conf_init_subsystem(void); -extern unsigned char conf_register_context(char *name, ctx_handler_t handler); -extern unsigned char conf_register_fstate(FILE *fp, char *path, char *outfile, unsigned long line, unsigned char flags); -extern unsigned char conf_register_builtin(char *name, eterm_func_ptr_t ptr); -extern unsigned char conf_register_context_state(unsigned char ctx_id); -extern void conf_free_subsystem(void); -extern char *shell_expand(char *); -extern char *conf_find_file(const char *file, const char *dir, const char *pathlist); -extern FILE *open_config_file(char *name); -extern char *conf_parse(char *conf_name, const char *dir, const char *path); extern char *conf_parse_theme(char **theme, char *conf_name, unsigned char fallback); extern void init_defaults(void); extern void post_parse(void); diff --git a/src/screen.c b/src/screen.c index 7c946b3..ffd22d7 100644 --- a/src/screen.c +++ b/src/screen.c @@ -225,7 +225,7 @@ scr_reset(void) D_SCREEN(("screen.text == %8p, screen.rend == %8p, swap.text == %8p, swap.rend == %8p\n", screen.text, screen.rend, swap.text, swap.rend)); /* we have fewer rows so fix up number of scrolled lines */ - MIN_IT(screen.row, TermWin.nrow - 1); + UPPER_BOUND(screen.row, TermWin.nrow - 1); } else if (TermWin.nrow > prev_nrow) { /* add rows */ @@ -583,7 +583,7 @@ scroll_text(int row1, int row2, int count, int spec) return 0; if ((count > 0) && (row1 == 0) && (current_screen == PRIMARY)) { TermWin.nscrolled += count; - MIN_IT(TermWin.nscrolled, TermWin.saveLines); + UPPER_BOUND(TermWin.nscrolled, TermWin.saveLines); } else if (!spec) row1 += TermWin.saveLines; row2 += TermWin.saveLines; @@ -612,7 +612,7 @@ scroll_text(int row1, int row2, int count, int spec) /* A: scroll up */ - MIN_IT(count, row2 - row1 + 1); + UPPER_BOUND(count, row2 - row1 + 1); /* A1: Copy and blank out lines that will get clobbered by the rotation */ for (i = 0, j = row1; i < count; i++, j++) { @@ -708,10 +708,8 @@ scr_add_lines(const unsigned char *str, int nlines, int len) screen.row -= nlines; } } - MIN_IT(screen.col, last_col - 1); - MIN_IT(screen.row, TermWin.nrow - 1); - /*MAX_IT(screen.row, 0); */ - MAX_IT(screen.row, -TermWin.nscrolled); + UPPER_BOUND(screen.col, last_col - 1); + BOUND(screen.row, -TermWin.nscrolled, TermWin.nrow - 1); row = screen.row + TermWin.saveLines; if (screen.text[row] == NULL) { @@ -755,7 +753,7 @@ scr_add_lines(const unsigned char *str, int nlines, int len) scr_tab(1); continue; case '\n': - MAX_IT(stp[last_col], screen.col); + LOWER_BOUND(stp[last_col], screen.col); screen.flags &= ~Screen_WrapNext; if (screen.row == screen.bscroll) { scroll_text(screen.tscroll, screen.bscroll, 1, 0); @@ -769,7 +767,7 @@ scr_add_lines(const unsigned char *str, int nlines, int len) srp = screen.rend[row]; /* _must_ refresh */ continue; case '\r': - MAX_IT(stp[last_col], screen.col); + LOWER_BOUND(stp[last_col], screen.col); screen.flags &= ~Screen_WrapNext; screen.col = 0; continue; @@ -813,7 +811,7 @@ scr_add_lines(const unsigned char *str, int nlines, int len) screen.flags &= ~Screen_WrapNext; } } - MAX_IT(stp[last_col], screen.col); + LOWER_BOUND(stp[last_col], screen.col); if (screen.col == 0) { end.col = last_col - 1; end.row = screen.row - 1; @@ -889,14 +887,11 @@ scr_tab(int count) void scr_gotorc(int row, int col, int relative) { - D_SCREEN(("scr_gotorc(r:%d,c:%d,%d): from (r:%d,c:%d)\n", row, col, relative, screen.row, screen.col)); - ZERO_SCROLLBACK; RESET_CHSTAT; screen.col = ((relative & C_RELATIVE) ? (screen.col + col) : col); - MAX_IT(screen.col, 0); - MIN_IT(screen.col, TermWin.ncol - 1); + BOUND(screen.col, 0, TermWin.ncol - 1); if (screen.flags & Screen_WrapNext) { screen.flags &= ~Screen_WrapNext; @@ -918,12 +913,11 @@ scr_gotorc(int row, int col, int relative) } else { if (screen.flags & Screen_Relative) { /* relative origin mode */ screen.row = row + screen.tscroll; - MIN_IT(screen.row, screen.bscroll); + UPPER_BOUND(screen.row, screen.bscroll); } else screen.row = row; } - MAX_IT(screen.row, 0); - MIN_IT(screen.row, TermWin.nrow - 1); + BOUND(screen.row, 0, TermWin.nrow - 1); } /* @@ -953,8 +947,7 @@ scr_index(int direction) blank_screen_mem(screen.text, screen.rend, dirn, rstyle); } else screen.row += dirn; - MAX_IT(screen.row, 0); - MIN_IT(screen.row, TermWin.nrow - 1); + BOUND(screen.row, 0, TermWin.nrow - 1); CHECK_SELECTION; } @@ -982,7 +975,7 @@ scr_erase_line(int mode) case 0: /* erase to end of line */ col = screen.col; num = TermWin.ncol - col; - MIN_IT(screen.text[row][TermWin.ncol], col); + UPPER_BOUND(screen.text[row][TermWin.ncol], col); break; case 1: /* erase to beginning of line */ col = 0; @@ -1050,7 +1043,7 @@ scr_erase_screen(int mode) return; } if (row >= 0 && row <= TermWin.nrow) { /* check OOB */ - MIN_IT(num, (TermWin.nrow - row)); + UPPER_BOUND(num, (TermWin.nrow - row)); if (rstyle & RS_RVid || rstyle & RS_Uline) ren = -1; else { @@ -1152,7 +1145,7 @@ scr_insdel_chars(int count, int insdel) return; CHECK_SELECTION; - MIN_IT(count, (TermWin.ncol - screen.col)); + UPPER_BOUND(count, (TermWin.ncol - screen.col)); row = screen.row + TermWin.saveLines; screen.flags &= ~Screen_WrapNext; @@ -1164,7 +1157,7 @@ scr_insdel_chars(int count, int insdel) screen.rend[row][col] = screen.rend[row][col - count]; } screen.text[row][TermWin.ncol] += count; - MIN_IT(screen.text[row][TermWin.ncol], TermWin.ncol); + UPPER_BOUND(screen.text[row][TermWin.ncol], TermWin.ncol); /* FALLTHROUGH */ case ERASE: blank_line(&(screen.text[row][screen.col]), @@ -1203,8 +1196,8 @@ scr_insdel_chars(int count, int insdel) void scr_scroll_region(int top, int bot) { - MAX_IT(top, 0); - MIN_IT(bot, TermWin.nrow - 1); + LOWER_BOUND(top, 0); + UPPER_BOUND(bot, TermWin.nrow - 1); if (top > bot) return; screen.tscroll = top; @@ -1502,8 +1495,7 @@ scr_move_to(int y, int len) / (len)) - (TermWin.nrow - 1); D_SCREEN(("scr_move_to(%d, %d) view_start:%d\n", y, len, TermWin.view_start)); - MAX_IT(TermWin.view_start, 0); - MIN_IT(TermWin.view_start, TermWin.nscrolled); + BOUND(TermWin.view_start, 0, TermWin.nscrolled); return (TermWin.view_start - start); } @@ -2224,8 +2216,7 @@ scr_search_scrollback(char *str) } else { if (lrow != rows) { TermWin.view_start = rows - lrow - TermWin.nrow; - LOWER_BOUND(TermWin.view_start, 0); - UPPER_BOUND(TermWin.view_start, TermWin.nscrolled); + BOUND(TermWin.view_start, 0, TermWin.nscrolled); D_SCREEN(("New view start is %d\n", TermWin.view_start)); } } @@ -2562,12 +2553,10 @@ selection_setclr(int set, int startr, int startc, int endr, int endc) } last_col = TermWin.ncol - 1; - MIN_IT(endc, last_col); - MIN_IT(startr, TermWin.nrow - 1); - MAX_IT(startr, -TermWin.nscrolled); - MIN_IT(endr, TermWin.nrow - 1); - MAX_IT(endr, -TermWin.nscrolled); - MAX_IT(startc, 0); + LOWER_BOUND(startc, 0); + UPPER_BOUND(endc, last_col); + BOUND(startr, -TermWin.nscrolled, TermWin.nrow - 1); + BOUND(endr, -TermWin.nscrolled, TermWin.nrow - 1); startr += TermWin.saveLines; endr += TermWin.saveLines; @@ -2627,8 +2616,7 @@ selection_start_colrow(int col, int row) selection.end.row, selection.end.col); } selection.op = SELECTION_INIT; - MAX_IT(row, 0); - MIN_IT(row, TermWin.nrow - 1); + BOUND(row, 0, TermWin.nrow - 1); row -= TermWin.view_start; end_col = screen.text[row + TermWin.saveLines][TermWin.ncol]; @@ -2710,7 +2698,7 @@ selection_make(Time tm) end_col = selection.end.col + 1; } else i = 1; - MIN_IT(end_col, TermWin.ncol); + UPPER_BOUND(end_col, TermWin.ncol); for (; col < end_col; col++) *str++ = *t++; if (!(Options & Opt_select_trailing_spaces)) { @@ -2971,8 +2959,7 @@ selection_extend(int x, int y, int flag) */ col = Pixel2Col(x); row = Pixel2Row(y); - MAX_IT(row, 0); - MIN_IT(row, TermWin.nrow - 1); + BOUND(row, 0, TermWin.nrow - 1); if (((selection.clicks % 3) == 1) && !flag && (col == selection.mark.col && (row == selection.mark.row + TermWin.view_start))) { /* select nothing */ selection_setclr(0, selection.beg.row, selection.beg.col, @@ -3033,8 +3020,7 @@ selection_extend_colrow(int col, int row, int flag, int cont) return; } old_col = col; - MAX_IT(col, -1); - MIN_IT(col, TermWin.ncol); + BOUND(col, -1, TermWin.ncol); old_beg.col = selection.beg.col; old_beg.row = selection.beg.row; old_end.col = selection.end.col; diff --git a/src/screen.h b/src/screen.h index 46d4fb1..c6aa1ba 100644 --- a/src/screen.h +++ b/src/screen.h @@ -29,11 +29,9 @@ #define IS_CUT_BUFFER(a) (((a) >= XA_CUT_BUFFER0) && ((a) <= XA_CUT_BUFFER7)) #define ZERO_SCROLLBACK do { \ - D_SCREEN(("ZERO_SCROLLBACK()\n")); \ if (Options & Opt_home_on_output) TermWin.view_start = 0; \ } while (0) #define REFRESH_ZERO_SCROLLBACK do { \ - D_SCREEN(("REFRESH_ZERO_SCROLLBACK()\n")); \ if (Options & Opt_home_on_output) TermWin.view_start = 0; \ } while (0) #define CHECK_SELECTION do { \ diff --git a/src/script.c b/src/script.c index 2fa3bc8..5dae3b9 100644 --- a/src/script.c +++ b/src/script.c @@ -50,6 +50,7 @@ static eterm_script_handler_t script_handlers[] = { "paste", script_handler_paste }, { "quit", script_handler_exit }, { "save", script_handler_save }, + { "scroll", script_handler_scroll }, { "search", script_handler_search }, { "spawn", script_handler_spawn }, @@ -122,6 +123,18 @@ eterm_handle_winop(char *action) #endif /********* HANDLERS **********/ + +/* copy(): Copy the current selection to the specified clipboard or cut + * buffer + * + * Syntax: copy([ ]) + * + * is either a number 0-7, in which case the selection is copied to + * the the cut buffer specified, or one of the words "clipboard," "primary," + * or "secondary" (or any initial substring thereof), in which case the + * selection is copied to the specified clipboard. The default buffer is + * the "primary" buffer (XA_PRIMARY in Xlib-speak). + */ void script_handler_copy(char **params) { @@ -149,6 +162,15 @@ script_handler_copy(char **params) selection_copy(sel); } +/* exit(): Exit Eterm with an optional message or return code + * + * Syntax: exit([ { | } ]) + * + * is an optional exit message. is a positive or + * negative integer return code. Either one may be specified, but not + * both. If neither is specified, Eterm exits with a return code of 0 + * and no message. + */ void script_handler_exit(char **params) { @@ -167,6 +189,17 @@ script_handler_exit(char **params) exit(code); } +/* paste(): Paste the contents of the specified clipboard or cut buffer + * into the terminal window + * + * Syntax: paste([ ]) + * + * is either a number 0-7, in which case the contents of the cut + * buffer specified are pasted, or one of the words "clipboard," "primary," + * or "secondary" (or any initial substring thereof), in which case the + * contents of the specified clipboard are pasted. The default buffer is + * the "primary" buffer (XA_PRIMARY in Xlib-speak). + */ void script_handler_paste(char **params) { @@ -194,6 +227,16 @@ script_handler_paste(char **params) selection_paste(sel); } +/* save(): Save the current theme/user configuration + * + * Syntax: save([ { theme | user } ,] [ ]) + * + * The "user" settings are saved by default, and the default + * filename is user.cfg. So save() by itself will save the + * current user settings to user.cfg. save(theme) will save + * the theme settings instead; the default filename in that case + * will be theme.cfg. + */ void script_handler_save(char **params) { @@ -208,12 +251,80 @@ script_handler_save(char **params) } } +/* scroll(): Scroll backward or forward in the scrollback buffer + * + * Syntax: scroll(N) or scroll(Nl) -- Scroll N lines + * scroll(Np) -- Scroll N pages/screensful + * scroll(Nb) -- Scroll N buffers + * + * N is a floating point number. Use a negative number to scroll + * up and a positive number to scroll down. Fractions can be used + * also (e.g., to scroll one half page, use scroll(0.5p)). It is + * possible to spell out "lines," "pages," and "buffers" as well, + * and the type may be passed as a second parameter if you wish. + */ +void +script_handler_scroll(char **params) +{ + char *type; + double cnt_float; + long count; + int direction = DN; + + if (params && *params) { + cnt_float = strtod(params[0], &type); + if (cnt_float == 0.0) { + return; + } else if (cnt_float < 0.0) { + cnt_float = -cnt_float; + direction = UP; + } + if (!type) { + type = params[1]; + } + if (type && *type) { + for (; *type && !isalpha(*type); type++); + if (str_leading_match("lines", type)) { + count = (long) cnt_float; + } else if (str_leading_match("pages", type) || str_leading_match("screens", type)) { + count = (long) ((cnt_float * TermWin.nrow) - CONTEXT_LINES); + } else if (str_leading_match("buffers", type)) { + count = (long) (cnt_float * (TermWin.nrow + TermWin.saveLines)); + } else { + print_error("Invalid modifier \"%s\" in scroll()\n", type); + return; + } + } else { + count = (long) cnt_float; + } + + if (count <= 0) { + return; + } + scr_page(direction, count); + } +} + +/* search(): Search the scrollback buffer for a string and highlight + * any occurances of it. + * + * Syntax: search([ ]) + * + * is an optional search string to highlight. If none is given, + * search() will clear the previously-highlighted search term. + */ void script_handler_search(char **params) { scr_search_scrollback(params ? params[0] : NULL); } +/* spawn(): Spawns a child process to execute a sub-command + * + * Syntax: spawn([ ]) + * + * If no command is specified, the default is to execute another Eterm. + */ void script_handler_spawn(char **params) { @@ -228,6 +339,12 @@ script_handler_spawn(char **params) } } +/* nop(): Do nothing + * + * Syntax: nop() + * + * This function can be used to cancel undesired default behavior. + */ void script_handler_nop(char **params) { diff --git a/src/script.h b/src/script.h index f4c9ea9..6e20949 100644 --- a/src/script.h +++ b/src/script.h @@ -47,6 +47,7 @@ extern void script_handler_copy(char **); extern void script_handler_exit(char **); extern void script_handler_paste(char **); extern void script_handler_save(char **); +extern void script_handler_scroll(char **); extern void script_handler_search(char **); extern void script_handler_spawn(char **); extern void script_handler_nop(char **); diff --git a/src/scrollbar.c b/src/scrollbar.c index fbc2012..1d70bcf 100644 --- a/src/scrollbar.c +++ b/src/scrollbar.c @@ -258,10 +258,10 @@ sb_handle_button_press(event_t *ev) if (scrollbar.type == SCROLLBAR_MOTIF || scrollbar.type == SCROLLBAR_NEXT) { if (scrollbar_is_above_anchor(ev->xany.window, ev->xbutton.y)) { scrollbar_draw_trough(IMAGE_STATE_CLICKED, 0); - scr_page(UP, TermWin.nrow - 1); + scr_page(UP, TermWin.nrow - CONTEXT_LINES); } else if (scrollbar_is_below_anchor(ev->xany.window, ev->xbutton.y)) { scrollbar_draw_trough(IMAGE_STATE_CLICKED, 0); - scr_page(DN, TermWin.nrow - 1); + scr_page(DN, TermWin.nrow - CONTEXT_LINES); } else { scrollbar_set_motion(1); } @@ -270,7 +270,7 @@ sb_handle_button_press(event_t *ev) #ifdef XTERM_SCROLLBAR if (scrollbar.type == SCROLLBAR_XTERM) { - scr_page((ev->xbutton.button == Button1 ? DN : UP), TermWin.nrow - 1); + scr_page((ev->xbutton.button == Button1 ? DN : UP), TermWin.nrow - CONTEXT_LINES); } #endif /* XTERM_SCROLLBAR */ break; diff --git a/src/startup.c b/src/startup.c index 7f74b34..570bec5 100644 --- a/src/startup.c +++ b/src/startup.c @@ -146,9 +146,6 @@ eterm_bootstrap(int argc, char *argv[]) props[PROP_DND_PROTOCOL] = XInternAtom(Xdisplay, "DndProtocol", False); props[PROP_DND_SELECTION] = XInternAtom(Xdisplay, "DndSelection", False); - /* Initialize the parser */ - conf_init_subsystem(); - if ((theme_dir = conf_parse_theme(&rs_theme, THEME_CFG, PARSE_TRY_ALL)) != NULL) { char *tmp; diff --git a/src/startup.h b/src/startup.h index bcfe3ee..5219c9c 100644 --- a/src/startup.h +++ b/src/startup.h @@ -44,38 +44,6 @@ #define MAX_COLS 250 #define MAX_ROWS 128 -#ifdef MIN -# undef MIN -#endif -#ifdef MAX -# undef MAX -#endif -#ifdef __GNUC__ -# define MIN(a,b) __extension__ ({__typeof__(a) aa = (a); __typeof__(b) bb = (b); (aa < bb) ? (aa) : (bb);}) -# define MAX(a,b) __extension__ ({__typeof__(a) aa = (a); __typeof__(b) bb = (b); (aa > bb) ? (aa) : (bb);}) -# define LOWER_BOUND(current, other) __extension__ ({__typeof__(other) o = (other); ((current) < o) ? ((current) = o) : (current);}) -# define AT_LEAST(current, other) LOWER_BOUND(current, other) -# define MAX_IT(current, other) LOWER_BOUND(current, other) -# define UPPER_BOUND(current, other) __extension__ ({__typeof__(other) o = (other); ((current) > o) ? ((current) = o) : (current);}) -# define AT_MOST(current, other) UPPER_BOUND(current, other) -# define MIN_IT(current, other) UPPER_BOUND(current, other) -# define BOUND(val, min, max) __extension__ ({__typeof__(min) m1 = (min); __typeof__(max) m2 = (max); ((val) < m1) ? ((val) = m1) : (((val) > m2) ? ((val) = m2) : (val));}) -# define CONTAIN(val, min, max) BOUND(val, min, max) -# define SWAP_IT(one, two, tmp) do {(tmp) = (one); (one) = (two); (two) = (tmp);} while (0) -#else -# define MIN(a,b) (((a) < (b)) ? (a) : (b)) -# define MAX(a,b) (((a) > (b)) ? (a) : (b)) -# define LOWER_BOUND(current, other) (((current) < (other)) ? ((current) = (other)) : (current)) -# define AT_LEAST(current, other) LOWER_BOUND(current, other) -# define MAX_IT(current, other) LOWER_BOUND(current, other) -# define UPPER_BOUND(current, other) (((current) > (other)) ? ((current) = (other)) : (current)) -# define AT_MOST(current, other) UPPER_BOUND(current, other) -# define MIN_IT(current, other) UPPER_BOUND(current, other) -# define BOUND(val, min, max) (((val) < (min)) ? ((val) = (min)) : (((val) > (max)) ? ((val) = (max)) : (val))) -# define CONTAIN(val, min, max) BOUND(val, min, max) -# define SWAP_IT(one, two, tmp) do {(tmp) = (one); (one) = (two); (two) = (tmp);} while (0) -#endif - #define SHADOW 2 /* convert pixel dimensions to row/column values */