Code

wreadln: removed the disabled ncursesw code
[ncmpc.git] / src / wreadln.c
1 /*
2  * (c) 2004 by Kalle Wallin <kaw@linux.se>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  * You should have received a copy of the GNU General Public License
14  * along with this program; if not, write to the Free Software
15  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16  *
17  */
19 #include "wreadln.h"
20 #include "charset.h"
21 #include "config.h"
23 #include <stdlib.h>
24 #include <string.h>
25 #include <glib.h>
27 #define KEY_CTRL_A   1
28 #define KEY_CTRL_B   2
29 #define KEY_CTRL_C   3
30 #define KEY_CTRL_D   4
31 #define KEY_CTRL_E   5
32 #define KEY_CTRL_F   6
33 #define KEY_CTRL_G   7
34 #define KEY_CTRL_K   11
35 #define KEY_CTRL_N   14
36 #define KEY_CTRL_P   16
37 #define KEY_CTRL_U   21
38 #define KEY_CTRL_Z   26
39 #define KEY_BCKSPC   8
40 #define TAB          9
42 #define WRLN_MAX_LINE_SIZE 1024
43 #define WRLN_MAX_HISTORY_LENGTH 32
44  
45 guint wrln_max_line_size = WRLN_MAX_LINE_SIZE;
46 guint wrln_max_history_length = WRLN_MAX_HISTORY_LENGTH;
47 wrln_wgetch_fn_t wrln_wgetch = NULL;
48 void *wrln_completion_callback_data = NULL;
49 wrln_gcmp_pre_cb_t wrln_pre_completion_callback = NULL;
50 wrln_gcmp_post_cb_t wrln_post_completion_callback = NULL;
52 extern void sigstop(void);
53 extern void screen_bell(void);
55 /* move the cursor one step to the right */
56 static inline void cursor_move_right(gint *cursor,
57                                      gint *start,
58                                      gint width,
59                                      gint x0,
60                                      gint x1,
61                                      gchar *line)
62 {
63         if (*cursor < (int)strlen(line) &&
64             *cursor < (int)wrln_max_line_size - 1) {
65                 (*cursor)++;
66                 if (*cursor + x0 >= x1 && *start < *cursor - width + 1)
67                         (*start)++;
68         }
69 }
71 /* move the cursor one step to the left */
72 static inline void cursor_move_left(gint *cursor,
73                                     gint *start)
74 {
75   if( *cursor > 0 )
76     {
77       if( *cursor==*start && *start > 0 )
78         (*start)--;
79       (*cursor)--;
80     }
81 }
83 /* move the cursor to the end of the line */
84 static inline void cursor_move_to_eol(gint *cursor,
85                                       gint *start,
86                                       gint width,
87                                       gint x0,
88                                       gint x1,
89                                       gchar *line)
90 {
91   *cursor = strlen(line);
92   if( *cursor+x0 >= x1 )
93     *start = *cursor-width+1;
94 }
96 /* draw line buffer and update cursor position */
97 static inline void drawline(gint cursor,
98                             gint start,
99                             gint width,
100                             gint x0,
101                             gint y,
102                             gboolean masked,
103                             gchar *line,
104                             WINDOW *w)
106   wmove(w, y, x0);
107   /* clear input area */
108   whline(w, ' ', width);
109   /* print visible part of the line buffer */
110   if(masked == TRUE) whline(w, '*', utf8_width(line) - start);
111   else waddnstr(w, line+start, width);
112   /* move the cursor to the correct position */
113   wmove(w, y, x0 + cursor-start);
114   /* tell ncurses to redraw the screen */
115   doupdate();
119 /* libcurses version */
121 static gchar *
122 _wreadln(WINDOW *w,
123          const gchar *prompt,
124          const gchar *initial_value,
125          gint x1,
126          GList **history,
127          GCompletion *gcmp,
128          gboolean masked)
130         GList *hlist = NULL, *hcurrent = NULL;
131         gchar *line;
132         gint x0, y, width;
133         gint cursor = 0, start = 0;
134         gint key = 0, i;
136         /* allocate a line buffer */
137         line = g_malloc0(wrln_max_line_size);
138         /* turn off echo */
139         noecho();
140         /* make shure the cursor is visible */
141         curs_set(1);
142         /* print prompt string */
143         if( prompt )
144                 waddstr(w, prompt);
145         /* retrive y and x0 position */
146         getyx(w, y, x0);
147         /* check the x1 value */
148         if( x1<=x0 || x1>COLS )
149                 x1 = COLS;
150         width = x1-x0;
151         /* clear input area */
152         mvwhline(w, y, x0, ' ', width);
154         if( history ) {
155                 /* append the a new line to our history list */
156                 *history = g_list_append(*history, g_malloc0(wrln_max_line_size));
157                 /* hlist points to the current item in the history list */
158                 hlist =  g_list_last(*history);
159                 hcurrent = hlist;
160         }
162         if( initial_value == (char *) -1 ) {
163                 /* get previous history entry */
164                 if( history && hlist->prev )
165                         {
166                                 if( hlist==hcurrent )
167                                         {
168                                                 /* save the current line */
169                                                 g_strlcpy(hlist->data, line, wrln_max_line_size);
170                                         }
171                                 /* get previous line */
172                                 hlist = hlist->prev;
173                                 g_strlcpy(line, hlist->data, wrln_max_line_size);
174                         }
175                 cursor_move_to_eol(&cursor, &start, width, x0, x1, line);
176                 drawline(cursor, start, width, x0, y, masked, line, w);
177         } else if( initial_value ) {
178                 /* copy the initial value to the line buffer */
179                 g_strlcpy(line, initial_value, wrln_max_line_size);
180                 cursor_move_to_eol(&cursor, &start, width, x0, x1, line);
181                 drawline(cursor, start, width, x0, y, masked, line, w);
182         }
184         while( key!=13 && key!='\n' ) {
185                 if( wrln_wgetch )
186                         key = wrln_wgetch(w);
187                 else
188                         key = wgetch(w);
190                 /* check if key is a function key */
191                 for(i=0; i<63; i++)
192                         if( key==KEY_F(i) ) {
193                                 key=KEY_F(1);
194                                 i=64;
195                         }
197                 switch (key) {
198 #ifdef HAVE_GETMOUSE
199                 case KEY_MOUSE: /* ignore mouse events */
200 #endif
201                 case ERR: /* ingnore errors */
202                         break;
204                 case TAB:
205                         if( gcmp ) {
206                                 char *prefix = NULL;
207                                 GList *list;
209                                 if(wrln_pre_completion_callback)
210                                         wrln_pre_completion_callback(gcmp, line,
211                                                                      wrln_completion_callback_data);
212                                 list = g_completion_complete(gcmp, line, &prefix);
213                                 if( prefix ) {
214                                         g_strlcpy(line, prefix, wrln_max_line_size);
215                                         cursor_move_to_eol(&cursor, &start, width, x0, x1, line);
216                                         g_free(prefix);
217                                 }
218                                 else
219                                         screen_bell();
220                                 if( wrln_post_completion_callback )
221                                         wrln_post_completion_callback(gcmp, line, list,
222                                                                       wrln_completion_callback_data);
223                         }
224                         break;
226                 case KEY_CTRL_G:
227                         screen_bell();
228                         g_free(line);
229                         if( history ) {
230                                 g_free(hcurrent->data);
231                                 hcurrent->data = NULL;
232                                 *history = g_list_delete_link(*history, hcurrent);
233                         }
234                         return NULL;
236                 case KEY_LEFT:
237                 case KEY_CTRL_B:
238                         cursor_move_left(&cursor, &start);
239                         break;
240                 case KEY_RIGHT:
241                 case KEY_CTRL_F:
242                         cursor_move_right(&cursor, &start, width, x0, x1, line);
243                         break;
244                 case KEY_HOME:
245                 case KEY_CTRL_A:
246                         cursor = 0;
247                         start = 0;
248                         break;
249                 case KEY_END:
250                 case KEY_CTRL_E:
251                         cursor_move_to_eol(&cursor, &start, width, x0, x1, line);
252                         break;
253                 case KEY_CTRL_K:
254                         line[cursor] = 0;
255                         break;
256                 case KEY_CTRL_U:
257                         cursor = utf8_width(line);
258                         for (i = 0;i < cursor; i++)
259                                 line[i] = '\0';
260                         cursor = 0;
261                         break;
262                 case 127:
263                 case KEY_BCKSPC:        /* handle backspace: copy all */
264                 case KEY_BACKSPACE:     /* chars starting from curpos */
265                         if( cursor > 0 ) {/* - 1 from buf[n+1] to buf   */
266                                 for (i = cursor - 1; line[i] != 0; i++)
267                                         line[i] = line[i + 1];
268                                 cursor_move_left(&cursor, &start);
269                         }
270                         break;
271                 case KEY_DC:            /* handle delete key. As above */
272                 case KEY_CTRL_D:
273                         if (cursor <= (gint)utf8_width(line) - 1) {
274                                 for (i = cursor; line[i] != 0; i++)
275                                         line[i] = line[i + 1];
276                         }
277                         break;
278                 case KEY_UP:
279                 case KEY_CTRL_P:
280                         /* get previous history entry */
281                         if( history && hlist->prev ) {
282                                 if( hlist==hcurrent )
283                                         {
284                                                 /* save the current line */
285                                                 g_strlcpy(hlist->data, line, wrln_max_line_size);
286                                         }
287                                 /* get previous line */
288                                 hlist = hlist->prev;
289                                 g_strlcpy(line, hlist->data, wrln_max_line_size);
290                         }
291                         cursor_move_to_eol(&cursor, &start, width, x0, x1, line);
292                         break;
293                 case KEY_DOWN:
294                 case KEY_CTRL_N:
295                         /* get next history entry */
296                         if( history && hlist->next ) {
297                                 /* get next line */
298                                 hlist = hlist->next;
299                                 g_strlcpy(line, hlist->data, wrln_max_line_size);
300                         }
301                         cursor_move_to_eol(&cursor, &start, width, x0, x1, line);
302                         break;
304                 case '\n':
305                 case 13:
306                 case KEY_IC:
307                 case KEY_PPAGE:
308                 case KEY_NPAGE:
309                 case KEY_F(1):
310                         /* ignore char */
311                         break;
312                 default:
313                         if (key >= 32) {
314                                 if (strlen (line + cursor)) { /* if the cursor is */
315                                         /* not at the last pos */
316                                         gchar *tmp = NULL;
317                                         gsize size = strlen(line + cursor) + 1;
319                                         tmp = g_malloc0(size);
320                                         g_strlcpy (tmp, line + cursor, size);
321                                         line[cursor] = key;
322                                         line[cursor + 1] = 0;
323                                         g_strlcat (&line[cursor + 1], tmp, size);
324                                         g_free(tmp);
325                                         cursor_move_right(&cursor, &start, width, x0, x1, line);
326                                 } else {
327                                         line[cursor + 1] = 0;
328                                         line[cursor] = key;
329                                         cursor_move_right(&cursor, &start, width, x0, x1, line);
330                                 }
331                         }
332                 }
334                 drawline(cursor, start, width, x0, y, masked, line, w);
335         }
337         /* update history */
338         if( history ) {
339                 if( strlen(line) ) {
340                         /* update the current history entry */
341                         size_t size = strlen(line)+1;
342                         hcurrent->data = g_realloc(hcurrent->data, size);
343                         g_strlcpy(hcurrent->data, line, size);
344                 } else {
345                         /* the line was empty - remove the current history entry */
346                         g_free(hcurrent->data);
347                         hcurrent->data = NULL;
348                         *history = g_list_delete_link(*history, hcurrent);
349                 }
351                 while( g_list_length(*history) > wrln_max_history_length ) {
352                         GList *first = g_list_first(*history);
354                         /* remove the oldest history entry  */
355                         g_free(first->data);
356                         first->data = NULL;
357                         *history = g_list_delete_link(*history, first);
358                 }
359         }
361         return g_realloc(line, strlen(line)+1);
364 gchar *
365 wreadln(WINDOW *w,
366         const gchar *prompt,
367         const gchar *initial_value,
368         gint x1,
369         GList **history,
370         GCompletion *gcmp)
372         return  _wreadln(w, prompt, initial_value, x1, history, gcmp, FALSE);
375 gchar *
376 wreadln_masked(WINDOW *w,
377                const gchar *prompt,
378                const gchar *initial_value,
379                gint x1,
380                GList **history,
381                GCompletion *gcmp)
383         return  _wreadln(w, prompt, initial_value, x1, history, gcmp, TRUE);