Code

Removed nested functions
[ncmpc.git] / src / wreadln.c
index 700769bd158175ebb1bd7644526fe3abccd1b776..8694bb367a8dcc8a531f1a4ae609ea9ace6115e0 100644 (file)
  *
  */
 
+#include "config.h"
+
 #include <stdlib.h>
 #include <string.h>
-#include <ncurses.h>
 #include <glib.h>
 
-#include "config.h"
+#ifdef USE_NCURSESW
+#include <ncursesw/ncurses.h>
+#else
+#include <ncurses.h>
+#endif
+
 #include "wreadln.h"
 
 #define KEY_CTRL_A   1
+#define KEY_CTRL_C   3
 #define KEY_CTRL_D   4 
 #define KEY_CTRL_E   5
 #define KEY_CTRL_G   7
 #define KEY_CTRL_K   11
+#define KEY_CTRL_Z   26
 #define KEY_BCKSPC   8
 #define TAB          9
 
 #define WRLN_MAX_LINE_SIZE 1024
 #define WRLN_MAX_HISTORY_LENGTH 32
  
-unsigned int wrln_max_line_size = WRLN_MAX_LINE_SIZE;
-unsigned int wrln_max_history_length = WRLN_MAX_HISTORY_LENGTH;
+guint wrln_max_line_size = WRLN_MAX_LINE_SIZE;
+guint wrln_max_history_length = WRLN_MAX_HISTORY_LENGTH;
 wrln_wgetch_fn_t wrln_wgetch = NULL;
+void *wrln_completion_callback_data = NULL;
 wrln_gcmp_pre_cb_t wrln_pre_completion_callback = NULL;
 wrln_gcmp_post_cb_t wrln_post_completion_callback = NULL;
 
+extern void sigstop(void);
 extern void screen_bell(void);
+extern size_t my_strlen(char *str);
 
-char *
-wreadln(WINDOW *w, 
-       char *prompt, 
-       char *initial_value,
-       int x1, 
+#ifndef USE_NCURSESW
+/* move the cursor one step to the right */
+static inline void cursor_move_right(gint *cursor,
+                                    gint *start,
+                                    gint width,
+                                    gint x0,
+                                    gint x1,
+                                    gchar *line)
+{
+  if( *cursor < strlen(line) && *cursor<wrln_max_line_size-1 )
+    {
+      (*cursor)++;
+      if( *cursor+x0 >= x1 && *start<*cursor-width+1)
+       (*start)++;
+    }
+}
+
+/* move the cursor one step to the left */
+static inline void cursor_move_left(gint *cursor,
+                                    gint *start)
+{
+  if( *cursor > 0 )
+    {
+      if( *cursor==*start && *start > 0 )
+       (*start)--;
+      (*cursor)--;
+    }
+}
+
+/* move the cursor to the end of the line */
+static inline void cursor_move_to_eol(gint *cursor,
+                                     gint *start,
+                                     gint width,
+                                     gint x0,
+                                     gint x1,
+                                     gchar *line)
+{
+  *cursor = strlen(line);
+  if( *cursor+x0 >= x1 )
+    *start = *cursor-width+1;
+}
+
+/* draw line buffer and update cursor position */
+static inline void drawline(gint cursor,
+                           gint start,
+                           gint width,
+                           gint x0,
+                           gint x1,
+                           gint y,
+                           gboolean masked,
+                           gchar *line,
+                           WINDOW *w)
+{
+  wmove(w, y, x0);
+  /* clear input area */
+  whline(w, ' ', width);
+  /* print visible part of the line buffer */
+  if(masked == TRUE) whline(w, '*', my_strlen(line)-start);
+  else waddnstr(w, line+start, width);
+  /* move the cursor to the correct position */
+  wmove(w, y, x0 + cursor-start);
+  /* tell ncurses to redraw the screen */
+  doupdate();
+}
+
+
+/* libcurses version */
+
+gchar *
+_wreadln(WINDOW *w, 
+       gchar *prompt, 
+       gchar *initial_value,
+       gint x1, 
        GList **history, 
-       GCompletion *gcmp)
+       GCompletion *gcmp,
+        gboolean masked)
 {
   GList *hlist = NULL, *hcurrent = NULL;
-  char *line;
-  int x0, y, width;            
-  int cursor = 0, start = 0;           
-  int key = 0, i;
-
-  /* move the cursor one step to the right */
-  void cursor_move_right(void) {
-    if( cursor < strlen(line) && cursor<wrln_max_line_size-1 )
-      {
-       cursor++;
-       if( cursor+x0 >= x1 && start<cursor-width+1)
-         start++;
-      }
-  }
-  /* move the cursor one step to the left */
-  void cursor_move_left(void) {
-    if( cursor > 0 )
-      {
-       if( cursor==start && start > 0 )
-         start--;
-       cursor--;
-      }
-  }
- /* move the cursor to the end of the line */
-  void cursor_move_to_eol(void) {
-    cursor = strlen(line);
-    if( cursor+x0 >= x1 )
-      start = cursor-width+1;
-  }
-  /* draw line buffer and update cursor position */
-  void drawline() {
-    wmove(w, y, x0);
-    /* clear input area */
-    whline(w, ' ', width);
-    /* print visible part of the line buffer */
-    waddnstr(w, line+start, width);
-    /* move the cursor to the correct position */
-    wmove(w, y, x0 + cursor-start);
-    /* tell ncurses to redraw the screen */
-    doupdate();
-  }
-
+  gchar *line;
+  gint x0, y, width;           
+  gint cursor = 0, start = 0;          
+  gint key = 0, i;
 
   /* allocate a line buffer */
   line = g_malloc0(wrln_max_line_size);
@@ -132,21 +174,21 @@ wreadln(WINDOW *w,
          if( hlist==hcurrent )
            {
              /* save the current line */
-             strncpy(hlist->data, line, wrln_max_line_size);
+             g_strlcpy(hlist->data, line, wrln_max_line_size);
            }
          /* get previous line */
          hlist = hlist->prev;
-         strncpy(line, hlist->data, wrln_max_line_size);
+         g_strlcpy(line, hlist->data, wrln_max_line_size);
        }
-      cursor_move_to_eol();
-      drawline();
+      cursor_move_to_eol(&cursor, &start, width, x0, x1, line);
+      drawline(cursor, start, width, x0, x1, y, masked, line, w);
     }
   else if( initial_value )
     {
       /* copy the initial value to the line buffer */
-      strncpy(line, initial_value, wrln_max_line_size);
-      cursor_move_to_eol();
-      drawline();
+      g_strlcpy(line, initial_value, wrln_max_line_size);
+      cursor_move_to_eol(&cursor, &start, width, x0, x1, line);
+      drawline(cursor, start, width, x0, x1, y, masked, line, w);
     }  
 
   while( key!=13 && key!='\n' )
@@ -166,7 +208,9 @@ wreadln(WINDOW *w,
 
       switch (key)
        {
+#ifdef HAVE_GETMOUSE
        case KEY_MOUSE: /* ignore mouse events */
+#endif
        case ERR: /* ingnore errors */
          break;
 
@@ -176,7 +220,7 @@ wreadln(WINDOW *w,
            {
              x1=COLS;
              width = x1-x0;
-             cursor_move_to_eol();
+             cursor_move_to_eol(&cursor, &start, width, x0, x1, line);
            }
          /* make shure the cursor is visible */
          curs_set(1);
@@ -189,19 +233,20 @@ wreadln(WINDOW *w,
              GList *list;
              
              if(wrln_pre_completion_callback)
-               wrln_pre_completion_callback(gcmp, line);
+               wrln_pre_completion_callback(gcmp, line,
+                                            wrln_completion_callback_data);
              list = g_completion_complete(gcmp, line, &prefix);              
              if( prefix )
                {
-                 int len = strlen(prefix);
-                 strncpy(line, prefix, len);
-                 cursor_move_to_eol();
+                 g_strlcpy(line, prefix, wrln_max_line_size);
+                 cursor_move_to_eol(&cursor, &start, width, x0, x1, line);
                  g_free(prefix);
                }
              else
                screen_bell();
              if( wrln_post_completion_callback )
-               wrln_post_completion_callback(gcmp, line, list);
+               wrln_post_completion_callback(gcmp, line, list,
+                                             wrln_completion_callback_data);
            }
          break;
 
@@ -217,10 +262,10 @@ wreadln(WINDOW *w,
          return NULL;
          
        case KEY_LEFT:
-         cursor_move_left();
+         cursor_move_left(&cursor, &start);
          break;
        case KEY_RIGHT: 
-         cursor_move_right();
+         cursor_move_right(&cursor, &start, width, x0, x1, line);
          break;
        case KEY_HOME:
        case KEY_CTRL_A:
@@ -229,7 +274,7 @@ wreadln(WINDOW *w,
          break;
        case KEY_END:
        case KEY_CTRL_E:
-         cursor_move_to_eol();
+         cursor_move_to_eol(&cursor, &start, width, x0, x1, line);
          break;
        case KEY_CTRL_K:
          line[cursor] = 0;
@@ -241,12 +286,12 @@ wreadln(WINDOW *w,
            {
              for (i = cursor - 1; line[i] != 0; i++)
                line[i] = line[i + 1];
-             cursor_move_left();
+             cursor_move_left(&cursor, &start);
            }
          break;
        case KEY_DC:            /* handle delete key. As above */
        case KEY_CTRL_D:
-         if( cursor <= strlen(line) - 1 ) 
+         if( cursor <= my_strlen(line) - 1 ) 
            {
              for (i = cursor; line[i] != 0; i++)
                line[i] = line[i + 1];
@@ -259,14 +304,13 @@ wreadln(WINDOW *w,
              if( hlist==hcurrent )
                {
                  /* save the current line */
-                 strncpy(hlist->data, line, wrln_max_line_size);
+                 g_strlcpy(hlist->data, line, wrln_max_line_size);
                }
              /* get previous line */
              hlist = hlist->prev;
-             strncpy(line, hlist->data, wrln_max_line_size);
+             g_strlcpy(line, hlist->data, wrln_max_line_size);
            }
-         //      if (cursor > strlen(line))
-         cursor_move_to_eol();
+         cursor_move_to_eol(&cursor, &start, width, x0, x1, line);
          break;
        case KEY_DOWN:  
          /* get next history entry */
@@ -274,9 +318,9 @@ wreadln(WINDOW *w,
            {
              /* get next line */
              hlist = hlist->next;
-             strncpy(line, hlist->data, wrln_max_line_size);
+             g_strlcpy(line, hlist->data, wrln_max_line_size);
            }
-         cursor_move_to_eol();
+         cursor_move_to_eol(&cursor, &start, width, x0, x1, line);
          break;
          
        case '\n':
@@ -292,25 +336,27 @@ wreadln(WINDOW *w,
            {
              if (strlen (line + cursor))       /* if the cursor is */
                {                               /* not at the last pos */
-                 char *tmp = 0;
-                 tmp = g_malloc0(strlen (line + cursor) + 1);
-                 strcpy (tmp, line + cursor);
+                 gchar *tmp = 0;
+                 gsize size = strlen(line + cursor) + 1;
+
+                 tmp = g_malloc0(size);
+                 g_strlcpy (tmp, line + cursor, size);
                  line[cursor] = key;
                  line[cursor + 1] = 0;
-                 strcat (&line[cursor + 1], tmp);
+                 g_strlcat (&line[cursor + 1], tmp, size);
                  g_free(tmp);
-                 cursor_move_right();
+                 cursor_move_right(&cursor, &start, width, x0, x1, line);
                }
              else
                {
                  line[cursor + 1] = 0;
                  line[cursor] = key;
-                 cursor_move_right();
+                 cursor_move_right(&cursor, &start, width, x0, x1, line);
                }
            }
        }
 
-      drawline();
+      drawline(cursor, start, width, x0, x1, y, masked, line, w);
     }
 
   /* update history */
@@ -321,7 +367,7 @@ wreadln(WINDOW *w,
          /* update the current history entry */
          size_t size = strlen(line)+1;
          hcurrent->data = g_realloc(hcurrent->data, size);
-         strncpy(hcurrent->data, line, size);
+         g_strlcpy(hcurrent->data, line, size);
        }
       else
        {
@@ -344,5 +390,409 @@ wreadln(WINDOW *w,
   
   return g_realloc(line, strlen(line)+1);
 }
+
+#else
+
+/* move the cursor one step to the right */
+static inline void cursor_move_right(gint *cursor,
+                                    gint *start,
+                                    gint width,
+                                    gint x0,
+                                    gint x1,
+                                    wchar_t *wline)
+{
+  if( *cursor < wcslen(wline) && *cursor<wrln_max_line_size-1 )
+    {
+      (*cursor)++;
+      if( *cursor+x0 >= x1 && *start<*cursor-width+1)
+       (*start)++;
+    }
+}
+
+/* move the cursor one step to the left */
+static inline void cursor_move_left(gint *cursor,
+                                   gint *start,
+                                   gint width,
+                                   gint x0,
+                                   gint x1,
+                                   wchar_t *line)
+{
+  if( *cursor > 0 )
+    {
+      if( *cursor==*start && *start > 0 )
+       (*start)--;
+      (*cursor)--;
+    }
+}
+
+
+static inline void backspace(gint *cursor,
+                            gint *start,
+                            gint width,
+                            gint x0,
+                            gint x1,
+                            wchar_t *wline) 
+{
+  int i;
+  if( *cursor > 0 )    
+    {
+      for (i = *cursor - 1; wline[i] != 0; i++)
+       wline[i] = wline[i + 1];
+      cursor_move_left(cursor, start, width, x0, x1, wline);
+    }
+}
+
+/* handle delete */
+static inline void delete(gint *cursor,
+                         wchar_t *wline) 
+{
+  int i;
+  if( *cursor <= wcslen(wline) - 1 ) 
+    {
+      for (i = *cursor; wline[i] != 0; i++)
+       wline[i] = wline[i + 1];
+    }
+}
+
+/* move the cursor to the end of the line */
+static inline void cursor_move_to_eol(gint *cursor,
+                                     gint *start,
+                                     gint width,
+                                     gint x0,
+                                     gint x1,
+                                     wchar_t *line)
+{
+  *cursor = wcslen(line);
+  if( *cursor+x0 >= x1 )
+    *start = *cursor-width+1;
+}
+
+/* draw line buffer and update cursor position */
+static inline void drawline(gint cursor,
+                           gint start,
+                           gint width,
+                           gint x0,
+                           gint x1,
+                           gint y,
+                           gboolean masked,
+                           wchar_t *line,
+                           WINDOW *w)
+{
+  wmove(w, y, x0);
+  /* clear input area */
+  whline(w, ' ', width);
+  /* print visible part of the line buffer */
+  if(masked == TRUE) whline(w, '*', wcslen(line)-start);
+  else waddnwstr(w, line+start, width);
+  FILE *dbg = fopen ("dbg", "a+");
+  fprintf (dbg, "%i,%s---%i---", width, line, wcslen (line));
+  /* move the cursor to the correct position */
+  wmove(w, y, x0 + cursor-start);
+  /* tell ncurses to redraw the screen */
+  doupdate();
+}
+
+/* libcursesw version */ 
+
+gchar *
+_wreadln(WINDOW *w, 
+       gchar *prompt, 
+       gchar *initial_value,
+       gint x1, 
+       GList **history, 
+       GCompletion *gcmp, 
+       gboolean masked)
+{
+  GList *hlist = NULL, *hcurrent = NULL;
+  wchar_t *wline;
+  gchar *mbline;
+  gint x0, x, y, width, start;
+  gint cursor;
+  wint_t wch;
+  gint key;
+  gint i;
+
+  /* initialize variables */
+  start = 0;
+  x = 0;
+  cursor = 0;
+  mbline = NULL;
+
+  /* allocate a line buffer */
+  wline = g_malloc0(wrln_max_line_size*sizeof(wchar_t));
+  /* turn off echo */
+  noecho();            
+  /* make shure the cursor is visible */
+  curs_set(1);
+  /* print prompt string */
+  if( prompt )
+    waddstr(w, prompt);        
+   /* retrive y and x0 position */
+  getyx(w, y, x0);
+  /* check the x1 value */
+  if( x1<=x0 || x1>COLS )
+    x1 = COLS;
+  width = x1-x0;
+  /* clear input area */
+  mvwhline(w, y, x0, ' ', width);
+
+
+  if( history )
+    {
+      /* append the a new line to our history list */
+      *history = g_list_append(*history, g_malloc0(wrln_max_line_size));
+      /* hlist points to the current item in the history list */
+      hlist =  g_list_last(*history);
+      hcurrent = hlist;
+    }
+  if( initial_value == (char *) -1 )
+    {
+      /* get previous history entry */
+      if( history && hlist->prev )
+       {
+         if( hlist==hcurrent )
+           {
+             /* save the current line */
+             //g_strlcpy(hlist->data, line, wrln_max_line_size);
+           }
+         /* get previous line */
+         hlist = hlist->prev;
+         mbstowcs(wline, hlist->data, wrln_max_line_size);
+       }
+      cursor_move_to_eol(&cursor, &start, width, x0, x1, wline);
+      drawline(cursor, start, width, x0, x1, y, masked, wline, w);
+    }
+  else if( initial_value )
+    {
+      /* copy the initial value to the line buffer */
+      mbstowcs(wline, initial_value, wrln_max_line_size);
+      cursor_move_to_eol(&cursor, &start, width, x0, x1, wline);
+      drawline(cursor, start, width, x0, x1, y, masked, wline, w);
+    }  
+
+  wch=0;
+  key=0;
+  while( wch!=13 && wch!='\n' )
+    {
+      key = wget_wch(w, &wch);
+
+      if( key==KEY_CODE_YES )
+       {
+         /* function key */
+         switch(wch)
+           {
+           case KEY_HOME:
+             x=0;
+             cursor=0;
+             start=0;
+             break;
+           case KEY_END:
+             cursor_move_to_eol(&cursor, &start, width, x0, x1, wline);
+             break;
+           case KEY_LEFT:
+             cursor_move_left(&cursor, &start, width, x0, x1, wline);
+             break;
+           case KEY_RIGHT:
+             cursor_move_right(&cursor, &start, width, x0, x1, wline);
+             break;
+           case KEY_DC:
+             delete(&cursor, wline);
+             break;
+           case KEY_BCKSPC:
+           case KEY_BACKSPACE: 
+             backspace(&cursor, &start, width, x0, x1, wline);
+             break;
+           case KEY_UP:                
+             /* get previous history entry */
+             if( history && hlist->prev )
+               {
+                 if( hlist==hcurrent )
+                   {
+                     /* save the current line */
+                     wcstombs(hlist->data, wline, wrln_max_line_size);
+                   }
+                 /* get previous line */
+                 hlist = hlist->prev;
+                 mbstowcs(wline, hlist->data, wrln_max_line_size);
+               }
+             cursor_move_to_eol(&cursor, &start, width, x0, x1, wline);
+             break; 
+           case KEY_DOWN:      
+             /* get next history entry */
+             if( history && hlist->next )
+               {
+                 /* get next line */
+                 hlist = hlist->next;
+                 mbstowcs(wline, hlist->data, wrln_max_line_size);
+               }
+             cursor_move_to_eol(&cursor, &start, width, x0, x1, wline);
+             break;
+           case KEY_RESIZE:
+             /* resize event */
+             if( x1>COLS )
+               {
+                 x1=COLS;
+                 width = x1-x0;
+                 cursor_move_to_eol(&cursor, &start, width, x0, x1, wline);
+               }
+             /* make shure the cursor is visible */
+             curs_set(1);
+             break;
+           }
+
+       }
+      else if( key!=ERR )
+       {
+         switch(wch)
+           {
+           case KEY_CTRL_A:
+             x=0;
+             cursor=0;
+             start=0;
+             break;
+           case KEY_CTRL_C:
+             exit(EXIT_SUCCESS);
+             break;
+           case KEY_CTRL_D:
+             delete(&cursor, wline);
+             break;
+           case KEY_CTRL_E:
+             cursor_move_to_eol(&cursor, &start, width, x0, x1, wline);
+             break;
+           case TAB:
+             if( gcmp )
+               {
+                 char *prefix = NULL;
+                 GList *list;
+                 
+                 i = wcstombs(NULL,wline,0)+1;
+                 mbline = g_malloc0(i);
+                 wcstombs(mbline, wline, i);
+                 
+                 if(wrln_pre_completion_callback)
+                   wrln_pre_completion_callback(gcmp, mbline, 
+                                                wrln_completion_callback_data);
+                 list = g_completion_complete(gcmp, mbline, &prefix);        
+                 if( prefix )
+                   {
+                     mbstowcs(wline, prefix, wrln_max_line_size);
+                     cursor_move_to_eol(&cursor, &start, width, x0, x1, wline);
+                     g_free(prefix);
+                   }
+                 else
+                   screen_bell();
+                 if( wrln_post_completion_callback )
+                   wrln_post_completion_callback(gcmp, mbline, list,
+                                                 wrln_completion_callback_data);
+                 
+                 g_free(mbline);
+               }
+             break;
+           case KEY_CTRL_G:
+             screen_bell();
+             g_free(wline);
+             if( history )
+               {
+                 g_free(hcurrent->data);
+                 hcurrent->data = NULL;
+                 *history = g_list_delete_link(*history, hcurrent);
+               }
+             return NULL;
+           case KEY_CTRL_K:
+             wline[cursor] = 0;
+             break;
+           case KEY_CTRL_Z:
+             sigstop();
+             break;
+           case 127:
+             backspace(&cursor, &start, width, x0, x1, wline);
+             break;
+           case '\n':
+           case 13:
+             /* ignore char */
+             break;
+           default:
+             if( (wcslen(wline+cursor)) )
+               {
+                 /* the cursor is not at the last pos */
+                 wchar_t *tmp = NULL;
+                 gsize len = (wcslen(wline+cursor)+1);
+                 tmp = g_malloc0(len*sizeof(wchar_t));
+                 wmemcpy(tmp, wline+cursor, len);
+                 wline[cursor] = wch;
+                 wline[cursor+1] = 0;
+                 wcscat(&wline[cursor+1], tmp);
+                 g_free(tmp);
+                 cursor_move_right(&cursor, &start, width, x0, x1, wline);
+               }
+             else
+               {
+                 FILE *ff = fopen ("curspr", "a+");
+                 fprintf (ff, "%i", cursor);
+                 wline[cursor] = wch;
+                 wline[cursor+1] = 0;
+                 cursor_move_right(&cursor, &start, width, x0, x1, wline);
+               }
+           }
+       }
+      drawline(cursor, start, width, x0, x1, y, masked, wline, w);
+    }
+  i = wcstombs(NULL,wline,0)+1;
+  mbline = g_malloc0(i);
+  wcstombs(mbline, wline, i);
+
+  /* update history */
+  if( history )
+    {
+      if( strlen(mbline) )
+       {
+         /* update the current history entry */
+         size_t size = strlen(mbline)+1;
+         hcurrent->data = g_realloc(hcurrent->data, size);
+         g_strlcpy(hcurrent->data, mbline, size);
+       }
+      else
+       {
+         /* the line was empty - remove the current history entry */
+         g_free(hcurrent->data);
+         hcurrent->data = NULL;
+         *history = g_list_delete_link(*history, hcurrent);
+       }
+
+      while( g_list_length(*history) > wrln_max_history_length )
+       {
+         GList *first = g_list_first(*history);
+
+         /* remove the oldest history entry  */
+         g_free(first->data);
+         first->data = NULL;
+         *history = g_list_delete_link(*history, first);
+       }
+    }
+  return mbline;
+}
  
+#endif
 
+gchar *
+wreadln(WINDOW *w, 
+       gchar *prompt, 
+       gchar *initial_value,
+       gint x1, 
+       GList **history, 
+       GCompletion *gcmp)
+  {
+    return  _wreadln(w, prompt, initial_value, x1, history, gcmp, FALSE);
+  }    
+       
+gchar *
+wreadln_masked(WINDOW *w, 
+       gchar *prompt, 
+       gchar *initial_value,
+       gint x1, 
+       GList **history, 
+       GCompletion *gcmp)
+  {
+    return  _wreadln(w, prompt, initial_value, x1, history, gcmp, TRUE);
+  }