From 046e3a75f70e6595c9228bb747613d8b4b56ce76 Mon Sep 17 00:00:00 2001 From: anon Date: Tue, 15 Aug 2023 10:56:04 +0200 Subject: [PATCH] . --- Makefile | 6 ++- README.md | 67 ++++++++++++++++-------------- config/colors.h | 3 ++ src/display.c | 28 ++++++++----- src/global.h | 10 ++--- src/history.c | 95 ------------------------------------------ src/input.c | 13 +++--- src/keys.h | 2 + src/mouse.c | 1 - src/readline.c | 125 ++++++++++++++++++++++++++++++++++++++++---------------- 10 files changed, 163 insertions(+), 187 deletions(-) delete mode 100644 src/history.c diff --git a/Makefile b/Makefile index 7657527..e52dcd6 100644 --- a/Makefile +++ b/Makefile @@ -1,12 +1,14 @@ DEBUG:=1 GCC:=0 +LIBS:=ncurses readline history + CC:=gcc CFLAGS:=-Wall -Wextra -Wpedantic CFLAGS +=$(if $(DEBUG),-O0 -ggdb,-O3 -flto=auto -fomit-frame-pointer) CFLAGS +=$(if $(SAN),-fsanitize=${SAN}) -CPPFLAGS:=-I config/ -I ${CHDRD} ${shell pkg-config --cflags ncurses readline} -LDLIBS=${shell pkg-config --libs ncurses readline} +CPPFLAGS:=-I config/ -I ${CHDRD} ${shell pkg-config --cflags ${LIBS}} +LDLIBS=${shell pkg-config --libs ${LIBS}} LEX:=flex LEXD:=src/ diff --git a/README.md b/README.md index 5febafa..1e7b532 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ Csope is alive and well. # Interface <-- Tab --> - +------------Message-------------+ +--------------------------------+ + +--Version-----------------Case--+ +--------------------------------+ A |+--------------+---------------+| |+------------------------------+| | || Input Window | Result window || || || | |+--------------+ || ? || || @@ -36,7 +36,7 @@ Csope is alive and well. | || | || || || | || | || || || V |+--------------+---------------+| |+------------------------------+| - +-----------Tool Tips------------+ +--------------------------------+ + +---------------------Tool Tips--+ +--------------------------------+ # Usacases Csope shines at exploring stranger and obsecure code bases due to its TUI. @@ -49,21 +49,29 @@ fixing it would have been a lost cause, if not for Cscope itself. Well, Csope no # Improvements/Changes ## User side -+ renamed the program, because "cscope" is annoying to type -+ improved gui -+ GNU Readline integration (ie. VI/EMACS mode, command history) /*pending*/ ++ Renamed the program, because "cscope" is annoying to type ++ Improved tui ++ GNU Readline/History integration ## To the code -+ nuked autoconf, replaced with single Makefile -+ reorganized main() -+ encapsulated changes to the TUI into display.c -+ encapsulated searching into find.c -+ removed "scanner.l" which seems to be an anchient version (and redundant copy) of "fscanner.l" forgotten by all -+ removed macro hell put in place to allow compiling on a dead badger -+ replaced repeated inline #ifdef KEY_\*-s with guaranteed definitions -+ removed random commets giving tips for and refering to specific issues -+ use stdbool instead of YES/NO macros -+ saved kilobytes by stripping trailing whitespace -+ FILE\* refsfound used to be rewind()-ed everytime the reads were not sequencial ++ Nuked autoconf, replaced with single Makefile ++ Reorganized the control flow ++ Encapsulated changes to the TUI into display.c ++ Encapsulated searching into find.c ++ Removed "scanner.l" which seems to be an anchient version (and redundant copy) of "fscanner.l" forgotten by all ++ Removed macro hell put in place to allow compiling on a dead badger ++ Use stdbool instead of YES/NO macros ++ Saved kilobytes by stripping trailing whitespace ++ ...and much more + +# Installation +You will have to compile from source. +After you made sure you have the following (dev) libraries installed: + ncurses + GNU Readline + GNU History (should come with Readline) +Just run: + make +This will yield the executable "scope", which you are free to do whatever with. # Control flow ... @@ -86,26 +94,25 @@ fixing it would have been a lost cause, if not for Cscope itself. Well, Csope no | int window_change | Bit mask type of the CH_\* macros. Keeps track of the windows to be refresed on the next run of display(). Could be better utalized. # TODO /*move soon*/ - + sort out constants.h - + scrollbar() uses magic int literals? - + Ordering function declarations in global.h by alpha order is not smart - + lineflagafterfile is stupid - + library.h...; "private library", in a program using 90 globals; ffs - + sort out the global hell - + was there really ever a scrollbar? - + handle resizing - + a search struct could be great for caching and could easy the global situation ++ sort out constants.h ++ scrollbar() uses magic int literals? ++ lineflagafterfile is stupid ++ library.h...; "private library", in a program using 90 globals; ffs ++ sort out the global hell ++ was there really ever a scrollbar? ++ handle resizing ++ a search struct could be great for caching and could ease the global situation ## Original + Same capabilities as interactive in non interactive (one shot) mode + Provide some how-do-I-use-this-thing doc. # BUGS - + Changing text double frees: - free(): double free detected in tcache 2 - Aborted - + Changing text can crash without replacing text and leaving the console ncursed - + After an attempted change malloc *can* cry and crash ++ Changing text double frees: + free(): double free detected in tcache 2 + Aborted ++ Changing text can crash without replacing text and leaving the console ncursed ++ After an attempted change malloc *can* cry and crash # Future features / contributor wishlist + providing support for other languages by integrating new lexers (e.g. ctag's) diff --git a/config/colors.h b/config/colors.h index e84305a..a621b54 100644 --- a/config/colors.h +++ b/config/colors.h @@ -35,6 +35,8 @@ # define COLOR_HELP_BG -1 # define COLOR_TOOLTIP_FG COLOR_WHITE # define COLOR_TOOLTIP_BG COLOR_GREEN +# define COLOR_CASE_FG COLOR_GREEN +# define COLOR_CASE_BG -1 # define COLOR_MESSAGE_FG COLOR_WHITE # define COLOR_MESSAGE_BG COLOR_BLACK # define COLOR_PATTERN_FG COLOR_WHITE @@ -78,6 +80,7 @@ enum color_pairs{ COLOR_PAIR_FIELD_SELECTED, COLOR_PAIR_HELP, COLOR_PAIR_TOOLTIP, + COLOR_PAIR_CASE, COLOR_PAIR_PATTERN, COLOR_PAIR_MESSAGE, COLOR_PAIR_TABLE_HEADER, diff --git a/src/display.c b/src/display.c index dca8765..7aa4a68 100644 --- a/src/display.c +++ b/src/display.c @@ -94,6 +94,7 @@ WINDOW *wresult; WINDOW *whelp; /* Non-Selectable windows */ WINDOW *wtooltip; +WINDOW *wcase; /* Selected window pointer */ WINDOW **current_window; static WINDOW **last_window; @@ -113,6 +114,7 @@ static inline void display_cursor(void); static inline void display_help(void); static inline void display_frame(const bool border_only); static inline void display_mode(void); +static inline void display_case(void); static inline void display_command_field(void); static inline void display_results(void); static inline void display_tooltip(void); @@ -161,6 +163,7 @@ void dispinit(void) { easy_init_pair(FIELD_SELECTED); easy_init_pair(HELP); easy_init_pair(TOOLTIP); + easy_init_pair(CASE); easy_init_pair(MESSAGE); easy_init_pair(PATTERN); easy_init_pair(TABLE_HEADER); @@ -189,6 +192,7 @@ void dispinit(void) { mdisprefs = result_window_height - (WRESULT_TABLE_BODY_START + 1); tooltip_width = MAX(MAX(strlen(tooltip_winput), strlen(tooltip_wmode)), strlen(tooltip_wresult)); + static int case_width = sizeof("Case: XXX")-1; if(mdisprefs <= 0) { postfatal(PROGRAM_NAME ": screen too small\n"); @@ -203,11 +207,12 @@ void dispinit(void) { rlinit(); /* initialize windows */ - winput = newwin(input_window_height, first_col_width, 1, 1); - wmode = newwin(mode_window_height, first_col_width, input_window_height + 1 + 1, 1); - wresult = newwin(result_window_height, second_col_width, 1, first_col_width + 1 + 1); - whelp = newwin(LINES - 2, COLS - 2, 1, 1); + winput = newwin(input_window_height, first_col_width, 1, 1); + wmode = newwin(mode_window_height, first_col_width, input_window_height + 1 + 1, 1); + wresult = newwin(result_window_height, second_col_width, 1, first_col_width + 1 + 1); + whelp = newwin(LINES - 2, COLS - 2, 1, 1); wtooltip = newwin(1, tooltip_width, LINES - 1, COLS - (tooltip_width + 4)); + wcase = newwin(1, case_width, 0, COLS - case_width - 4); refresh(); current_window = &winput; @@ -261,6 +266,13 @@ static inline void display_help() { do_press_any_key = true; } +static inline void display_case(){ + wmove(wcase, 0, 0); + wattron(wcase, COLOR_PAIR(COLOR_PAIR_CASE)); + waddstr(wcase, (caseless ? "Case: OFF" : "Case: ON")); + wattroff(wcase, COLOR_PAIR(COLOR_PAIR_CASE)); +} + static inline void display_frame(const bool border_only) { wattron(stdscr, COLOR_PAIR(COLOR_PAIR_FRAME)); @@ -273,12 +285,6 @@ static inline void display_frame(const bool border_only) { #else wprintw(stdscr, PROGRAM_NAME " version %d%s", FILEVERSION, FIXVERSION); #endif - wmove(stdscr, 0, COLS - (int)sizeof("Case: XXX") - 4); - if(caseless) { - waddstr(stdscr, "Case: ON"); - } else { - waddstr(stdscr, "Case: OFF"); - } /* --- */ if(!border_only) { /* Vertical line */ @@ -805,6 +811,7 @@ void display(void) { lstwin = *current_window; display_tooltip(); } + if(window_change & CH_CASE) { display_case(); } if(window_change & CH_INPUT) { display_command_field(); } if(window_change & CH_RESULT) { display_results(); } if(window_change & CH_MODE) { display_mode(); } @@ -814,6 +821,7 @@ void display(void) { wrefresh(wmode); wrefresh(wresult); wrefresh(wtooltip); + wrefresh(wcase); } window_change = CH_NONE; diff --git a/src/global.h b/src/global.h index bef5974..e2bfbac 100644 --- a/src/global.h +++ b/src/global.h @@ -80,8 +80,9 @@ enum { CH_RESULT = 0x0001 << 0, CH_INPUT = 0x0001 << 1, CH_MODE = 0x0001 << 2, - CH_HELP = 0x0001 << 3, /* do NOT add to CH_ALL */ - CH_ALL = CH_RESULT | CH_INPUT | CH_MODE + CH_CASE = 0x0001 << 3, + CH_HELP = 0x0001 << 4, /* do NOT add to CH_ALL */ + CH_ALL = CH_RESULT | CH_INPUT | CH_MODE | CH_CASE }; enum { @@ -252,7 +253,6 @@ void PCS_reset(void); void rlinit(void); -void addcmd(int f, char *s); void addsrcfile(char *path); void askforchar(void); void askforreturn(void); @@ -295,7 +295,6 @@ void posterr(char *msg, ...); void postfatal(const char *msg, ...); void putposting(char *term, int type); void fetch_string_from_dbase(char *, size_t); -void resetcmd(void); void shellpath(char *out, int limit, char *in); void sourcedir(char *dirlist); void myungetch(int c); @@ -309,9 +308,6 @@ bool writerefsfound(void); int findinit(const char *pattern_); MOUSE *getmouseaction(char leading_char); -struct cmd *currentcmd(void); -struct cmd *prevcmd(void); -struct cmd *nextcmd(void); int egrep(char *file, FILE *output, char *format); int hash(char *ss); diff --git a/src/history.c b/src/history.c deleted file mode 100644 index c969ba1..0000000 --- a/src/history.c +++ /dev/null @@ -1,95 +0,0 @@ -/*=========================================================================== - Copyright (c) 1998-2000, The Santa Cruz Operation - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - *Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - *Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - *Neither name of The Santa Cruz Operation nor the names of its contributors - may be used to endorse or promote products derived from this software - without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS - IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT falseT LIMITED TO, - THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT falseT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) - HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH - DAMAGE. - =========================================================================*/ - -/* cscope - interactive C symbol or text cross-reference - * - * command history - */ - -#include "global.h" - - - -static struct cmd *tail, *current; - -/* add a cmd to the history list */ -void addcmd(int f, char *s) /* field number and command text */ -{ - struct cmd *h; - - h = malloc(sizeof(struct cmd)); - if(tail) { - tail->next = h; - h->next = 0; - h->prev = tail; - tail = h; - } else { - tail = h; - h->next = h->prev = 0; - } - h->field = f; - h->text = strdup(s); - current = 0; -} - -/* return previous history item */ -struct cmd *prevcmd(void) { - if(current) { - if(current->prev) /* stay on first item */ - return current = current->prev; - else - return current; - } else if(tail) - return current = tail; - else - return NULL; -} - -/* return next history item */ -struct cmd *nextcmd(void) { - if(current) { - if(current->next) /* stay on first item */ - return current = current->next; - else - return current; - } else - return NULL; -} - -/* reset current to tail */ -void resetcmd(void) { - current = 0; -} - -struct cmd *currentcmd(void) { - return current; -} diff --git a/src/input.c b/src/input.c index fffc894..41295ff 100644 --- a/src/input.c +++ b/src/input.c @@ -160,17 +160,14 @@ static int wmode_input(const int c) { case KEY_DOWN: case KEY_RIGHT: field = (field + 1) % FIELDS; - resetcmd(); break; case ctrl('P'): /* go to previous input field */ case KEY_UP: case KEY_LEFT: field = (field + (FIELDS - 1)) % FIELDS; - resetcmd(); break; case KEY_HOME: /* go to first input field */ field = 0; - resetcmd(); break; case KEY_LL: /* go to last input field */ curdispline = disprefs; @@ -206,7 +203,6 @@ static int wresult_input(const int c) { break; case KEY_LL: field = FIELDS - 1; - resetcmd(); break; default: if(c > mdisprefs) { goto noredisp; } @@ -230,12 +226,10 @@ static int global_input(const int c) { break; case ctrl('K'): field = (field + (FIELDS - 1)) % FIELDS; - resetcmd(); window_change |= CH_MODE; break; case ctrl('J'): field = (field + 1) % FIELDS; - resetcmd(); window_change |= CH_MODE; break; case ctrl('H'): /* display previous page */ @@ -361,6 +355,13 @@ static int global_input(const int c) { case ctrl('E'): /* edit all lines */ editall(); break; + case ctrl('S'): // toggle caseless + caseless = !caseless; + egrepcaseless(caseless); + window_change |= CH_CASE; + break; + case EOF: + myexit(0); default: return 0; } diff --git a/src/keys.h b/src/keys.h index 3556aa0..ccd89ce 100644 --- a/src/keys.h +++ b/src/keys.h @@ -1,6 +1,8 @@ #ifndef KEYS_H #define KEYS_H +#include + /* Key macros */ /* These macros are not guaranteed to be defined, * however we wish to test for these anyways while diff --git a/src/mouse.c b/src/mouse.c index e9f860c..77299e6 100644 --- a/src/mouse.c +++ b/src/mouse.c @@ -420,7 +420,6 @@ int process_mouse() { field = p->y1 - FLDLINE; /* force it into range */ if(field >= FIELDS) { field = FIELDS - 1; } - resetcmd(); return (false); } diff --git a/src/readline.c b/src/readline.c index 08c83bc..062d6e6 100644 --- a/src/readline.c +++ b/src/readline.c @@ -1,18 +1,65 @@ #include #include +#include #include "global.h" #include "build.h" #include static int input_available = 0; -static char input_char; +static int input_char; char input_line[PATLEN + 1]; +/* used for saving a line not [Enter]-ed yet, + * so its not lost if the user scrolls the history + */ +static struct PARTIAL_LINE { + bool is_active; + char* line; + int pos; +} partial_line = { + .line = NULL, + .is_active = true +}; + + +static inline void previous_history_proxy(void); +static inline void next_history_proxy(void); +static inline int rebuild_reference(void); + bool interpret(int c) { - input_char = c; - input_available = 1; - rl_callback_read_char(); + /* A switch is faster then binding Readline to a billion functions + * and since KEY_* values can't be bound anyways (values too large + * (because while the first argument of rl_bind_key() is an int, + * only unsigned chars are valid)), handling everything here + * creates consistency too. + */ + switch(c){ + case KEY_BACKSPACE: + rl_rubout(1, 0); + break; + case KEY_UP: + previous_history_proxy(); + break; + case KEY_DOWN: + next_history_proxy(); + break; + case ctrl('R'): + rebuild_reference(); + break; + case ESC: + case ctrl('X'): + process_mouse(); + break; + default: + input_char = c; + input_available = 1; + rl_callback_read_char(); + return 0; + } + //XXX: + // rl_bind_key(ctrl('\\'), /**/); /* bypass bindings */ + window_change |= CH_INPUT; return 0; } @@ -20,7 +67,7 @@ static int getc_function(FILE *ignore) { UNUSED(ignore); input_available = 0; - return (int)input_char; + return input_char; } static int input_available_hook() { @@ -34,6 +81,8 @@ static void redisplay_function() { static void callback_handler(char *line) { if(!line) { return; } + add_history(line); + switch(input_mode) { case INPUT_NORMAL: strncpy(input_line, line, PATLEN); @@ -62,24 +111,7 @@ static void callback_handler(char *line) { } } -static int ctrl_z() { - kill(0, SIGTSTP); - return 0; -} - -static int toggle_caseless() { - if(caseless == false) { - caseless = true; - postmsg2("Caseless mode is now ON"); - } else { - caseless = false; - postmsg2("Caseless mode is now OFF"); - } - egrepcaseless(caseless); /* turn on/off -i flag */ - return 0; -} - -static int rebuild_reference() { +static inline int rebuild_reference() { if(isuptodate == true) { postmsg("The -d option prevents rebuilding the symbol database"); return (false); @@ -99,7 +131,41 @@ static int rebuild_reference() { return (true); } +static inline void previous_history_proxy(){ + HIST_ENTRY* i = previous_history(); + if(i){ + if(partial_line.is_active){ + free(partial_line.line); + partial_line = (struct PARTIAL_LINE){ + .line = rl_line_buffer, + .pos = rl_point, + .is_active = false + }; + }else{ + free(rl_line_buffer); + } + // + rl_line_buffer = strdup(i->line); + rl_point = strlen(rl_line_buffer); + } +} + +static inline void next_history_proxy(){ + HIST_ENTRY* i = next_history(); + if(i){ + free(rl_line_buffer); + rl_line_buffer = strdup(i->line); + rl_point = strlen(rl_line_buffer); + }else if(!partial_line.is_active){ + rl_line_buffer = strdup(partial_line.line); + rl_point = partial_line.pos; + partial_line.is_active = true; + } +} + void rlinit() { + using_history(); + rl_catch_signals = 0; rl_catch_sigwinch = 0; rl_prep_term_function = NULL; @@ -110,17 +176,4 @@ void rlinit() { rl_input_available_hook = input_available_hook; rl_redisplay_function = redisplay_function; rl_callback_handler_install("", callback_handler); - - rl_bind_key(7, - rl_rubout); // XXX: 7 is backspace for some reason (on my system anyways?) - rl_bind_key(KEY_BACKSPACE, rl_rubout); - - rl_bind_key(EOF, myexit); - rl_bind_key(ctrl('Z'), ctrl_z); - rl_bind_key(ctrl('Z'), toggle_caseless); - rl_bind_key(ctrl('R'), rebuild_reference); - rl_bind_key(ESC, process_mouse); /* possible unixpc mouse selection */ - rl_bind_key(ctrl('X'), process_mouse); /* mouse selection */ - - // rl_bind_key(ctrl('\\'), /**/); /* bypass bindings */ }