Code

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