From: Timo Korvola Date: Sat, 3 Mar 2018 22:04:40 +0000 (+0200) Subject: Fix history by borrowing from curses. X-Git-Url: https://scope-eye.net/git/?a=commitdiff_plain;h=a8d187d0f873eed40580e0bd5756a0c042af380f;p=liskon_frotz.git Fix history by borrowing from curses. --- diff --git a/src/common/frotz.h b/src/common/frotz.h index bfa287e..dc15729 100644 --- a/src/common/frotz.h +++ b/src/common/frotz.h @@ -5,6 +5,9 @@ * */ +#ifndef FROTZ_H_ +#define FROTZ_H_ + /* Unfortunately, frotz's bool definition conflicts with that of curses. But since no os_* function uses it, it's safe to let the frotz core see this definition, but have the unix port see the curses version. */ @@ -812,3 +815,5 @@ void resize_screen(void); /* This is callable only from resize_screen. */ bool os_repaint_window (int win, int ypos_old, int ypos_new, int xpos, int ysize, int xsize); + +#endif diff --git a/src/sdl/generic.c b/src/sdl/generic.c index 42abf2f..2e531f6 100644 --- a/src/sdl/generic.c +++ b/src/sdl/generic.c @@ -13,6 +13,7 @@ #include "../blorb/blorb.h" #include "../common/frotz.h" +#include "generic.h" FILE *blorb_fp; bb_result_t blorb_res; @@ -252,4 +253,90 @@ void os_warn (const char *s, ...) if (len > sizeof(buf)) os_display_string((zchar *)"(truncated)\n"); new_line(); -}/* os_warn */ +} + +/* These are useful for circular buffers. + */ +#define RING_DEC( ptr, beg, end) (ptr > (beg) ? --ptr : (ptr = (end))) +#define RING_INC( ptr, beg, end) (ptr < (end) ? ++ptr : (ptr = (beg))) + +#define MAX_HISTORY 256 +static char *history_buffer[MAX_HISTORY]; +static char **history_next = history_buffer; /* Next available slot. */ +static char **history_view = history_buffer; /* What the user is looking at. */ +#define history_end (history_buffer + MAX_HISTORY - 1) + + +/** + * Add the given string to the next available history buffer slot. + */ +void gen_add_to_history(zchar *str) +{ + + if (*history_next != NULL) + free( *history_next); + *history_next = (char *)malloc(strlen((char *)str) + 1); + strcpy( *history_next, (char *)str); + RING_INC( history_next, history_buffer, history_end); + history_view = history_next; /* Reset user frame after each line */ + + return; +} + + +/** + * Reset the view to the end of history. + */ +void gen_history_reset() +{ + history_view = history_next; +} + + +/** + * Copy last available string to str, if possible. Return 1 if successful. + * Only lines of at most maxlen characters will be considered. In addition + * the first searchlen characters of the history entry must match those of str. + */ +int gen_history_back(zchar *str, int searchlen, int maxlen) +{ + char **prev = history_view; + + do { + RING_DEC(history_view, history_buffer, history_end); + if ((history_view == history_next) + || (*history_view == NULL)) { + os_beep(BEEP_HIGH); + history_view = prev; + return 0; + } + } while (strlen(*history_view) > (size_t)maxlen + || (searchlen != 0 + && strncmp((char *)str, *history_view, searchlen))); + strcpy((char *)str + searchlen, *history_view + searchlen); + return 1; +} + + +/** + * Opposite of gen_history_back, and works in the same way. + */ +int gen_history_forward(zchar *str, int searchlen, int maxlen) +{ + char **prev = history_view; + + do { + RING_INC(history_view, history_buffer, history_end); + if ((history_view == history_next) + || (*history_view == NULL)) { + + os_beep(BEEP_HIGH); + history_view = prev; + return 0; + } + } while (strlen(*history_view) > (size_t) maxlen + || (searchlen != 0 + && strncmp((char *)str, *history_view, searchlen))); + strcpy((char *)str + searchlen, *history_view + searchlen); + return 1; +} diff --git a/src/sdl/sf_video.c b/src/sdl/sf_video.c index 4ff8229..d2a9dc1 100644 --- a/src/sdl/sf_video.c +++ b/src/sdl/sf_video.c @@ -7,6 +7,8 @@ #include +#include "generic.h" + #include "sf_frotz.h" static SDL_Rect blitrect = {0,0,0,0}; @@ -720,27 +722,6 @@ zchar os_read_key(int timeout, int cursor) return sf_read_key(timeout,cursor,0); } -#define MAXHISTORY 8192 -static zword History[MAXHISTORY] = {0}; -static int histptr = 0; -static void addtoHistory( zchar *buf) - { - int n = mywcslen(buf)+2; - int avail = MAXHISTORY - histptr; - if (n <= 2) return; - while (avail < n) - { - int k; - if (histptr == 0) return; - k = History[histptr-1]+2; - histptr -= k; - } - if (histptr) memmove(History+n,History,histptr*sizeof(zword)); - histptr += n; - n -= 2; - History[0] = History[n+1] = n; - memcpy(History+1,buf,n*sizeof(zword)); - } /* * os_read_line @@ -788,182 +769,130 @@ static void addtoHistory( zchar *buf) * */ zchar os_read_line(int max, zchar *buf, int timeout, int width, int continued) - { - static int prev_pos = 0; - static int prev_history = -1; - int pos = 0; - int history = -1; - int ptx,pty; - SF_textsetting * ts = sf_curtextsetting(); - SDL_Event event; - -//printf("os_read_line mx%d buf[0]%d tm%d w%d c%d\n",max,buf[0],timeout,width,continued); -// LineInput line; - sf_flushtext(); -// theWnd->ResetOverhang(); -// theWnd->UpdateMenus(); -// theWnd->RecaseInput(buf); - - // Find the editing position - if (continued) - { - if (prev_pos <= (int)mywcslen(buf)) - pos = prev_pos; - } - else - pos = mywcslen(buf); - -//printf("pos %d\n",pos); - // Find the input history position - if (continued) - history = prev_history; - - // Draw the input line - ptx = ts->cx; - pty = ts->cy; -// CPoint point = theWnd->GetTextPoint(); - ptx -= os_string_width(buf); //theWnd->GetTextWidth(buf,mywcslen(buf)); - sf_DrawInput(buf,pos,ptx,pty,width,true); +{ + static int pos = 0, searchpos = -1; + int ptx,pty; + int len = mywcslen(buf); + SF_textsetting * ts = sf_curtextsetting(); + SDL_Event event; + + //printf("os_read_line mx%d buf[0]%d tm%d w%d c%d\n",max,buf[0],timeout,width,continued); + // LineInput line; + sf_flushtext(); + // theWnd->ResetOverhang(); + // theWnd->UpdateMenus(); + // theWnd->RecaseInput(buf); + + /* Better be careful here or it might segv. I wonder if we should just + ignore 'continued' and check for len > 0 instead? Might work better + with Beyond Zork. */ + if (!continued || pos > len || searchpos > len) { + pos = len; + gen_history_reset(); /* Reset user's history view. */ + searchpos = -1; /* -1 means initialize from len. */ + } - if (timeout) mytimeout = sf_ticks() + m_timerinterval*timeout; -// InputTimer timer(timeout); - while (true) - { - // Get the next input - while (SDL_PollEvent(&event)) - { - zword c; - if ((c = goodzkey(&event,1))) - { -//printf("goodzk %4x\n",c); - if (c == ZC_BACKSPACE) - { - // Delete the character to the left of the cursor - if (pos > 0) - { - memmove(buf+pos-1,buf+pos,sizeof(zword)*(mywcslen(buf)-pos+1)); - pos--; - sf_DrawInput(buf,pos,ptx,pty,width,true); - } - } - else if (c == VK_TAB) - { - if (pos == (int)mywcslen(buf)) - { - zchar extension[10], *s; - completion(buf,extension); - - // Add the completion to the input stream - for (s = extension; *s != 0; s++) - if (sf_IsValidChar(*s)) - buf[pos++] = (*s); - buf[pos] = 0; - sf_DrawInput(buf,pos,ptx,pty,width,true); - } - } - else if ((c == ZC_ARROW_LEFT)) - { - // Move the cursor left - if (pos > 0) - pos--; - sf_DrawInput(buf,pos,ptx,pty,width,true); - } - else if ((c == ZC_ARROW_RIGHT)) - { - // Move the cursor right - if (pos < (int)mywcslen(buf)) - pos++; - sf_DrawInput(buf,pos,ptx,pty,width,true); - } - else if ((c == ZC_ARROW_UP)) - { - int n; zword *p; - // Move up through the command history - if (history >= 0) - { - n = History[history]; - if (n) history += (n+2); - } - else - history = 0; - n = History[history]; - p = History + history + 1; - pos = 0; - while (n) { buf[pos++] = *p++; n--;} - buf[pos] = 0; - sf_DrawInput(buf,pos,ptx,pty,width,true); - } - else if ((c == ZC_ARROW_DOWN)) - { - // Move down through the command history - pos = 0; - if (history > 0) - { - int n; zword *p; - n = History[history-1]; - history -= (n+2); - p = History + history + 1; - while (n) { buf[pos++] = *p++; n--; } - } - else - history = -1; - buf[pos] = 0; - sf_DrawInput(buf,pos,ptx,pty,width,true); - } - else if (is_terminator(c)) - { - // Terminate the current input - m_exitPause = false; - sf_DrawInput(buf,pos,ptx,pty,width,false); - - if ((c == ZC_SINGLE_CLICK) || (c == ZC_DOUBLE_CLICK)) - { -/* mouse_x = input.mousex+1; + // Draw the input line + ptx = ts->cx; + pty = ts->cy; + // CPoint point = theWnd->GetTextPoint(); + ptx -= os_string_width(buf); //theWnd->GetTextWidth(buf,mywcslen(buf)); + sf_DrawInput(buf,pos,ptx,pty,width,true); + + if (timeout) mytimeout = sf_ticks() + m_timerinterval*timeout; + // InputTimer timer(timeout); + while (true) { + // Get the next input + while (SDL_PollEvent(&event)) { + zword c; + if ((c = goodzkey(&event,1))) { + //printf("goodzk %4x\n",c); + switch (c) { + case ZC_BACKSPACE: + // Delete the character to the left of the cursor + if (pos > 0) { + memmove(buf+pos-1,buf+pos,sizeof(zword)*(mywcslen(buf)-pos+1)); + pos--; + sf_DrawInput(buf,pos,ptx,pty,width,true); + } + break; + case VK_TAB: + if (pos == (int)mywcslen(buf)) { + zchar extension[10], *s; + completion(buf,extension); + + // Add the completion to the input stream + for (s = extension; *s != 0; s++) + if (sf_IsValidChar(*s)) + buf[pos++] = (*s); + buf[pos] = 0; + sf_DrawInput(buf,pos,ptx,pty,width,true); + } + break; + case ZC_ARROW_LEFT: + // Move the cursor left + if (pos > 0) + pos--; + sf_DrawInput(buf,pos,ptx,pty,width,true); + break; + case ZC_ARROW_RIGHT: + // Move the cursor right + if (pos < (int)mywcslen(buf)) + pos++; + sf_DrawInput(buf,pos,ptx,pty,width,true); + break; + case ZC_ARROW_UP: + case ZC_ARROW_DOWN: + if (searchpos < 0) + searchpos = mywcslen(buf); + if ((c == ZC_ARROW_UP + ? gen_history_back : gen_history_forward)( + buf, searchpos, max)) { + pos = mywcslen(buf); + sf_DrawInput(buf,pos,ptx,pty,width,true); + } + break; + default: + if (is_terminator(c)) { + // Terminate the current input + m_exitPause = false; + sf_DrawInput(buf,pos,ptx,pty,width,false); + + if ((c == ZC_SINGLE_CLICK) || (c == ZC_DOUBLE_CLICK)) { + /* mouse_x = input.mousex+1; mouse_y = input.mousey+1;*/ - } - else if (c == ZC_RETURN) - addtoHistory(buf); //theWnd->AddToInputHistory(buf); - -// theWnd->SetLastInput(buf); - prev_pos = pos; - prev_history = history; - return c; - } - else if (sf_IsValidChar(c)) - { - // Add a valid character to the input line - if ((int)mywcslen(buf) < max) - { - // Get the width of the new input line - int len = os_string_width(buf); - len += os_char_width(c); - len += os_char_width('0'); - -//printf("l%d w%d p%d\n",len,width,pos); - // Only allow if the width limit is not exceeded - if (len <= width) - { - memmove(buf+pos+1,buf+pos,sizeof(zword)*(mywcslen(buf)-pos+1)); - *(buf+pos) = c; - pos++; - sf_DrawInput(buf,pos,ptx,pty,width,true); - } - } - } - } - } - if ((timeout) && (sf_ticks() >= mytimeout)) - { - prev_pos = pos; - prev_history = history; - return ZC_TIME_OUT; - } - sf_checksound(); - sf_sleep(10); + } else if (c == ZC_RETURN) + gen_add_to_history(buf); + // theWnd->SetLastInput(buf); + return c; + } else if (sf_IsValidChar(c) && mywcslen(buf) < max) { + // Add a valid character to the input line + // Get the width of the new input line + int len = os_string_width(buf); + len += os_char_width(c); + len += os_char_width('0'); + + //printf("l%d w%d p%d\n",len,width,pos); + // Only allow if the width limit is not exceeded + if (len <= width) { + memmove(buf+pos+1,buf+pos,sizeof(zword)*(mywcslen(buf)-pos+1)); + *(buf+pos) = c; + pos++; + sf_DrawInput(buf,pos,ptx,pty,width,true); + } + } + } + } + } + if ((timeout) && (sf_ticks() >= mytimeout)) { + return ZC_TIME_OUT; + } + sf_checksound(); + sf_sleep(10); } - return 0; - } + return 0; +} // Draw the current input line void sf_DrawInput(zchar * buffer, int pos, int ptx, int pty, int width, bool cursor)