#include "../blorb/blorb.h"
#include "../common/frotz.h"
+#include "generic.h"
FILE *blorb_fp;
bb_result_t blorb_res;
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;
+}
\r
#include <SDL.h>\r
\r
+#include "generic.h"\r
+\r
#include "sf_frotz.h"\r
\r
static SDL_Rect blitrect = {0,0,0,0};\r
return sf_read_key(timeout,cursor,0);\r
}\r
\r
-#define MAXHISTORY 8192\r
-static zword History[MAXHISTORY] = {0};\r
-static int histptr = 0;\r
-static void addtoHistory( zchar *buf)\r
- {\r
- int n = mywcslen(buf)+2;\r
- int avail = MAXHISTORY - histptr;\r
- if (n <= 2) return;\r
- while (avail < n)\r
- {\r
- int k;\r
- if (histptr == 0) return;\r
- k = History[histptr-1]+2;\r
- histptr -= k;\r
- }\r
- if (histptr) memmove(History+n,History,histptr*sizeof(zword));\r
- histptr += n;\r
- n -= 2;\r
- History[0] = History[n+1] = n;\r
- memcpy(History+1,buf,n*sizeof(zword));\r
- }\r
\r
/*\r
* os_read_line\r
*\r
*/\r
zchar os_read_line(int max, zchar *buf, int timeout, int width, int continued)\r
- {\r
- static int prev_pos = 0;\r
- static int prev_history = -1;\r
- int pos = 0;\r
- int history = -1;\r
- int ptx,pty;\r
- SF_textsetting * ts = sf_curtextsetting();\r
- SDL_Event event;\r
-\r
-//printf("os_read_line mx%d buf[0]%d tm%d w%d c%d\n",max,buf[0],timeout,width,continued);\r
-// LineInput line;\r
- sf_flushtext();\r
-// theWnd->ResetOverhang();\r
-// theWnd->UpdateMenus();\r
-// theWnd->RecaseInput(buf);\r
-\r
- // Find the editing position\r
- if (continued)\r
- {\r
- if (prev_pos <= (int)mywcslen(buf))\r
- pos = prev_pos;\r
- }\r
- else\r
- pos = mywcslen(buf);\r
-\r
-//printf("pos %d\n",pos);\r
- // Find the input history position\r
- if (continued)\r
- history = prev_history;\r
-\r
- // Draw the input line\r
- ptx = ts->cx;\r
- pty = ts->cy;\r
-// CPoint point = theWnd->GetTextPoint();\r
- ptx -= os_string_width(buf); //theWnd->GetTextWidth(buf,mywcslen(buf));\r
- sf_DrawInput(buf,pos,ptx,pty,width,true);\r
+{\r
+ static int pos = 0, searchpos = -1;\r
+ int ptx,pty;\r
+ int len = mywcslen(buf);\r
+ SF_textsetting * ts = sf_curtextsetting();\r
+ SDL_Event event;\r
+\r
+ //printf("os_read_line mx%d buf[0]%d tm%d w%d c%d\n",max,buf[0],timeout,width,continued);\r
+ // LineInput line;\r
+ sf_flushtext();\r
+ // theWnd->ResetOverhang();\r
+ // theWnd->UpdateMenus();\r
+ // theWnd->RecaseInput(buf);\r
+\r
+ /* Better be careful here or it might segv. I wonder if we should just\r
+ ignore 'continued' and check for len > 0 instead? Might work better\r
+ with Beyond Zork. */\r
+ if (!continued || pos > len || searchpos > len) {\r
+ pos = len;\r
+ gen_history_reset(); /* Reset user's history view. */\r
+ searchpos = -1; /* -1 means initialize from len. */\r
+ }\r
\r
- if (timeout) mytimeout = sf_ticks() + m_timerinterval*timeout;\r
-// InputTimer timer(timeout);\r
- while (true)\r
- {\r
- // Get the next input\r
- while (SDL_PollEvent(&event)) \r
- {\r
- zword c;\r
- if ((c = goodzkey(&event,1))) \r
- {\r
-//printf("goodzk %4x\n",c);\r
- if (c == ZC_BACKSPACE)\r
- {\r
- // Delete the character to the left of the cursor\r
- if (pos > 0)\r
- {\r
- memmove(buf+pos-1,buf+pos,sizeof(zword)*(mywcslen(buf)-pos+1));\r
- pos--;\r
- sf_DrawInput(buf,pos,ptx,pty,width,true);\r
- }\r
- }\r
- else if (c == VK_TAB)\r
- {\r
- if (pos == (int)mywcslen(buf))\r
- {\r
- zchar extension[10], *s;\r
- completion(buf,extension);\r
-\r
- // Add the completion to the input stream\r
- for (s = extension; *s != 0; s++)\r
- if (sf_IsValidChar(*s))\r
- buf[pos++] = (*s);\r
- buf[pos] = 0;\r
- sf_DrawInput(buf,pos,ptx,pty,width,true);\r
- }\r
- }\r
- else if ((c == ZC_ARROW_LEFT))\r
- {\r
- // Move the cursor left\r
- if (pos > 0)\r
- pos--;\r
- sf_DrawInput(buf,pos,ptx,pty,width,true);\r
- }\r
- else if ((c == ZC_ARROW_RIGHT))\r
- {\r
- // Move the cursor right\r
- if (pos < (int)mywcslen(buf))\r
- pos++;\r
- sf_DrawInput(buf,pos,ptx,pty,width,true);\r
- }\r
- else if ((c == ZC_ARROW_UP))\r
- {\r
- int n; zword *p;\r
- // Move up through the command history\r
- if (history >= 0)\r
- {\r
- n = History[history];\r
- if (n) history += (n+2);\r
- }\r
- else\r
- history = 0;\r
- n = History[history];\r
- p = History + history + 1;\r
- pos = 0;\r
- while (n) { buf[pos++] = *p++; n--;}\r
- buf[pos] = 0;\r
- sf_DrawInput(buf,pos,ptx,pty,width,true);\r
- }\r
- else if ((c == ZC_ARROW_DOWN))\r
- {\r
- // Move down through the command history\r
- pos = 0;\r
- if (history > 0)\r
- {\r
- int n; zword *p;\r
- n = History[history-1];\r
- history -= (n+2);\r
- p = History + history + 1;\r
- while (n) { buf[pos++] = *p++; n--; }\r
- }\r
- else\r
- history = -1;\r
- buf[pos] = 0;\r
- sf_DrawInput(buf,pos,ptx,pty,width,true);\r
- }\r
- else if (is_terminator(c))\r
- {\r
- // Terminate the current input\r
- m_exitPause = false;\r
- sf_DrawInput(buf,pos,ptx,pty,width,false);\r
-\r
- if ((c == ZC_SINGLE_CLICK) || (c == ZC_DOUBLE_CLICK))\r
- {\r
-/* mouse_x = input.mousex+1;\r
+ // Draw the input line\r
+ ptx = ts->cx;\r
+ pty = ts->cy;\r
+ // CPoint point = theWnd->GetTextPoint();\r
+ ptx -= os_string_width(buf); //theWnd->GetTextWidth(buf,mywcslen(buf));\r
+ sf_DrawInput(buf,pos,ptx,pty,width,true);\r
+\r
+ if (timeout) mytimeout = sf_ticks() + m_timerinterval*timeout;\r
+ // InputTimer timer(timeout);\r
+ while (true) {\r
+ // Get the next input\r
+ while (SDL_PollEvent(&event)) {\r
+ zword c;\r
+ if ((c = goodzkey(&event,1))) {\r
+ //printf("goodzk %4x\n",c);\r
+ switch (c) {\r
+ case ZC_BACKSPACE:\r
+ // Delete the character to the left of the cursor\r
+ if (pos > 0) {\r
+ memmove(buf+pos-1,buf+pos,sizeof(zword)*(mywcslen(buf)-pos+1));\r
+ pos--;\r
+ sf_DrawInput(buf,pos,ptx,pty,width,true);\r
+ }\r
+ break;\r
+ case VK_TAB:\r
+ if (pos == (int)mywcslen(buf)) {\r
+ zchar extension[10], *s;\r
+ completion(buf,extension);\r
+\r
+ // Add the completion to the input stream\r
+ for (s = extension; *s != 0; s++)\r
+ if (sf_IsValidChar(*s))\r
+ buf[pos++] = (*s);\r
+ buf[pos] = 0;\r
+ sf_DrawInput(buf,pos,ptx,pty,width,true);\r
+ }\r
+ break;\r
+ case ZC_ARROW_LEFT:\r
+ // Move the cursor left\r
+ if (pos > 0)\r
+ pos--;\r
+ sf_DrawInput(buf,pos,ptx,pty,width,true);\r
+ break;\r
+ case ZC_ARROW_RIGHT:\r
+ // Move the cursor right\r
+ if (pos < (int)mywcslen(buf))\r
+ pos++;\r
+ sf_DrawInput(buf,pos,ptx,pty,width,true);\r
+ break;\r
+ case ZC_ARROW_UP:\r
+ case ZC_ARROW_DOWN:\r
+ if (searchpos < 0)\r
+ searchpos = mywcslen(buf);\r
+ if ((c == ZC_ARROW_UP\r
+ ? gen_history_back : gen_history_forward)(\r
+ buf, searchpos, max)) {\r
+ pos = mywcslen(buf);\r
+ sf_DrawInput(buf,pos,ptx,pty,width,true);\r
+ }\r
+ break;\r
+ default:\r
+ if (is_terminator(c)) {\r
+ // Terminate the current input\r
+ m_exitPause = false;\r
+ sf_DrawInput(buf,pos,ptx,pty,width,false);\r
+\r
+ if ((c == ZC_SINGLE_CLICK) || (c == ZC_DOUBLE_CLICK)) {\r
+ /* mouse_x = input.mousex+1;\r
mouse_y = input.mousey+1;*/\r
- }\r
- else if (c == ZC_RETURN)\r
- addtoHistory(buf); //theWnd->AddToInputHistory(buf);\r
-\r
-// theWnd->SetLastInput(buf);\r
- prev_pos = pos;\r
- prev_history = history;\r
- return c;\r
- }\r
- else if (sf_IsValidChar(c))\r
- {\r
- // Add a valid character to the input line\r
- if ((int)mywcslen(buf) < max)\r
- {\r
- // Get the width of the new input line\r
- int len = os_string_width(buf);\r
- len += os_char_width(c);\r
- len += os_char_width('0');\r
-\r
-//printf("l%d w%d p%d\n",len,width,pos);\r
- // Only allow if the width limit is not exceeded\r
- if (len <= width)\r
- {\r
- memmove(buf+pos+1,buf+pos,sizeof(zword)*(mywcslen(buf)-pos+1));\r
- *(buf+pos) = c;\r
- pos++;\r
- sf_DrawInput(buf,pos,ptx,pty,width,true);\r
- }\r
- }\r
- }\r
- }\r
- }\r
- if ((timeout) && (sf_ticks() >= mytimeout))\r
- {\r
- prev_pos = pos;\r
- prev_history = history;\r
- return ZC_TIME_OUT;\r
- }\r
- sf_checksound();\r
- sf_sleep(10);\r
+ } else if (c == ZC_RETURN)\r
+ gen_add_to_history(buf);\r
+ // theWnd->SetLastInput(buf);\r
+ return c;\r
+ } else if (sf_IsValidChar(c) && mywcslen(buf) < max) {\r
+ // Add a valid character to the input line\r
+ // Get the width of the new input line\r
+ int len = os_string_width(buf);\r
+ len += os_char_width(c);\r
+ len += os_char_width('0');\r
+\r
+ //printf("l%d w%d p%d\n",len,width,pos);\r
+ // Only allow if the width limit is not exceeded\r
+ if (len <= width) {\r
+ memmove(buf+pos+1,buf+pos,sizeof(zword)*(mywcslen(buf)-pos+1));\r
+ *(buf+pos) = c;\r
+ pos++;\r
+ sf_DrawInput(buf,pos,ptx,pty,width,true);\r
+ }\r
+ }\r
+ }\r
+ }\r
+ }\r
+ if ((timeout) && (sf_ticks() >= mytimeout)) {\r
+ return ZC_TIME_OUT;\r
+ }\r
+ sf_checksound();\r
+ sf_sleep(10);\r
}\r
\r
- return 0;\r
- }\r
+ return 0;\r
+}\r
\r
// Draw the current input line\r
void sf_DrawInput(zchar * buffer, int pos, int ptx, int pty, int width, bool cursor)\r