]> git.deb.at Git - pkg/abook.git/blob - estr.c
1939af0d81ddf4d723e8826f724ccf98471789d7
[pkg/abook.git] / estr.c
1
2 /*
3  * $Id$
4  *  
5  * by JH <jheinonen@users.sourceforge.net>
6  *
7  * Copyright (C) Jaakko Heinonen
8  */
9
10
11 #define USE_FILESEL     1
12 /*#undef USE_FILESEL*/
13
14 #define ABOOK_SRC       1
15 /*#undef ABOOK_SRC*/
16
17 #include <stdlib.h>
18 #include <ctype.h>
19 #include <string.h>
20 #ifdef ABOOK_SRC
21 #       include "abook_curses.h"
22 #       include "options.h"
23 #else
24 #       include <ncurses.h>
25 #endif
26 #ifdef HAVE_CONFIG_H
27 #       include "config.h"
28 #endif
29 #include "estr.h"
30
31 #if defined(HAVE_LOCALE_H) || defined(HAVE_SETLOCALE)
32 #       include <locale.h>
33 #else
34 /*
35  * this is a quick and dirty hack and it is
36  * not likely to work well
37  */
38 #       undef iscntrl
39 #       undef isprint
40 #       define iscntrl(X)       (X < 32)
41 #       define isprint(X)       (!iscntrl(X))
42 #endif
43
44 /*
45  * hmmm, these should be universal and nice :)
46  */
47
48 #define         XCTRL(x) ((x) & 31)
49
50 #define         ENTER_KEY       KEY_ENTER
51 #define         BACKSPACE_KEY   KEY_BACKSPACE
52 #define         CANCEL_KEY      XCTRL('g')
53 #define         TAB_KEY         '\t'
54
55 #ifdef ABOOK_SRC
56 #       include "abook.h"
57 #       define MALLOC(X)        abook_malloc(X)
58 #       define REALLOC(X, XX)   abook_realloc(X, XX)
59 #else
60 #       define MALLOC(X)        malloc(X)
61 #       define REALLOC(X, XX)   realloc(X, XX)
62 #endif
63
64 /* introduce filesel */
65 #ifdef USE_FILESEL
66 char            *filesel();
67 #endif
68
69 #define INITIAL_BUFSIZE         100
70
71 char *
72 wenter_string(WINDOW *win, const int maxlen, const int flags)
73 {
74         int i = 0;
75         int y, x;
76         int ch;
77         char *str = NULL;
78         int size = maxlen > 0 ? maxlen + 1 : INITIAL_BUFSIZE; 
79
80         getyx(win, y, x);
81         str = MALLOC(size);
82
83         for( ;; ) { /* main loop */
84                 if(flags & ESTR_DONT_WRAP && x+i>COLS-2) {
85                         mvwaddnstr(win, y, x, str+(1+x+i-COLS), COLS-x-1);
86                         wmove(win, y, COLS-1);
87                         wclrtoeol(win);
88                 } else
89                         wmove(win, y, x + i);
90
91                 wrefresh(win);
92
93                 switch( (ch = getch()) ) {
94                         case ENTER_KEY:
95                         case 10:
96                         case 13:
97                                 goto out;
98                         case BACKSPACE_KEY:
99                         case 127:
100                                 if(i > 0)
101                                         mvwdelch(win, y, x + --i);
102                                 continue;       
103                         case CANCEL_KEY:
104                                 free(str);
105                                 return NULL;
106 #ifdef USE_FILESEL
107                         case TAB_KEY:
108                                 if( ! (flags & ESTR_USE_FILESEL) )
109                                         continue;
110                                 i = -1;
111                                 free(str);
112                                 str = filesel();
113                                 goto out;
114 #endif
115                 }
116                 if( !isprint(ch) || iscntrl(ch)
117                         || (maxlen > 0 && i + 1 > maxlen) )
118                         continue;
119                 str[i++] = ch;
120                 waddch(win,ch);
121                 if( i + 1 > size )
122                         str = REALLOC( str, size *= 2 );
123                 if( maxlen > 0 && i > maxlen)
124                         break;
125         }
126 out:
127         if( i >= 0 && str != NULL )
128                 str[i] = 0;
129         
130         return str;
131 }
132
133
134 #ifdef USE_FILESEL
135
136 /*
137  * filesel.c
138  * by JH <jheinonen@users.sourceforge.net>
139  *
140  * Copyright (C) Jaakko Heinonen
141  */
142
143 #include <stdio.h>
144 #include <dirent.h>
145 #include <stdlib.h>
146 #include <sys/stat.h>
147 #include <unistd.h>
148
149
150 #define FILESEL_STATUSLINE      2
151
152 #define FILESEL_LIST_TOP        4
153 #define FILESEL_LIST_BOTTOM     (LINES-2)
154
155 #define FILESEL_LIST_LINES      (FILESEL_LIST_BOTTOM-FILESEL_LIST_TOP)
156 #define FILESEL_LIST_COLS       COLS
157
158 #define FILESEL_LAST_LIST_ITEM  ( filesel_first_list_item + FILESEL_LIST_LINES - 1 )
159
160
161 #define FLSL_TYPE_DIR           0
162 #define FLSL_TYPE_OTHER         1
163
164 struct filesel_list_item {
165         char filename[256];
166         char type;
167 };
168
169 #ifndef ABOOK_SRC
170
171 #include <errno.h>
172
173 static char *
174 my_getcwd()
175 {
176         char *dir = NULL;
177         int size = 100;
178
179         dir = MALLOC(size);
180
181         while( getcwd(dir, size) == NULL && errno == ERANGE )
182                 dir = REALLOC(dir, size *= 2);
183
184         return dir;
185 }
186
187 #else
188 #       include "misc.h"
189 #endif
190
191
192 #define FILESEL_LAST_ITEM       (filesel_items -1)
193
194 int filesel_curitem = -1;
195 int filesel_first_list_item = -1;
196
197 int filesel_items=0;
198 struct filesel_list_item *lst = NULL ;
199
200 int filesel_list_capacity = 0;
201
202 WINDOW *filesel_list;
203
204 static void
205 filesel_close_list()
206 {
207         free(lst);
208         lst = NULL;
209         filesel_items = 0;
210         filesel_first_list_item = filesel_curitem = -1;
211         filesel_list_capacity = 0;
212 }
213
214 static void
215 filesel_init_list()
216 {
217         filesel_list = newwin(FILESEL_LIST_LINES, FILESEL_LIST_COLS,
218                         FILESEL_LIST_TOP, 0);
219 }
220
221 static void
222 init_filesel()
223 {
224         if( isendwin() ) {
225                 initscr();
226         }
227         
228         cbreak(); noecho();
229         nonl();
230         intrflush(stdscr, FALSE);
231         keypad(stdscr, TRUE);
232         filesel_init_list();
233         clear();
234 }
235
236 static void
237 close_filesel()
238 {
239         filesel_close_list();
240         delwin(filesel_list);
241         clear();
242         refresh();
243         endwin();
244 }
245
246 static void
247 filesel_check_list()
248 {
249         if( filesel_curitem < 0 && filesel_first_list_item < 0 && filesel_items > 0 )
250                 filesel_curitem = filesel_first_list_item = 0;
251 }
252
253
254 static int
255 filesel_add_filesel_list_item(struct filesel_list_item item)
256 {
257         if( ++filesel_items > filesel_list_capacity) {
258                 filesel_list_capacity =
259                 filesel_list_capacity < 1 ? 30:filesel_list_capacity << 1;
260                 lst = REALLOC(lst, filesel_list_capacity *
261                         sizeof(struct filesel_list_item) );
262         }
263
264         lst[FILESEL_LAST_ITEM] = item;
265
266         filesel_check_list();
267         
268         return 0;
269 }
270
271
272 #define FILESEL_DIRS_FIRST
273 #define FILESEL_ALPHABETIC_ORDER
274
275 #ifdef FILESEL_ALPHABETIC_ORDER
276 #       ifndef FILESEL_DIRS_FIRST
277 #               define FILESEL_DIRS_FIRST
278 #       endif
279 #endif
280
281 #ifdef FILESEL_ALPHABETIC_ORDER
282 static int
283 filenamecmp(const void *a, const void *b)
284 {
285         return strcmp( ((struct filesel_list_item *)a) -> filename,
286                         ((struct filesel_list_item *)b) -> filename );
287 }
288 #endif
289
290 static void
291 filesel_sort_list()
292 {
293 #ifdef FILESEL_DIRS_FIRST
294         int i, j, fdp=0;
295         struct filesel_list_item tmp;
296
297         while(lst[fdp].type == FLSL_TYPE_DIR)
298                 if( ++fdp >= FILESEL_LAST_ITEM )
299                         return;
300
301         for(i = fdp + 1; i < filesel_items; i++) {
302                 if(lst[i].type == FLSL_TYPE_DIR ) {
303                         tmp = lst[fdp];
304                         lst[fdp++] = lst[i];
305                         for( j = i; j > fdp ; j--)
306                                 lst[j] = lst[j - 1];
307                         lst[fdp] = tmp;
308                 }
309         }
310 #endif
311 #ifdef FILESEL_ALPHABETIC_ORDER
312 #ifdef ABOOK_SRC
313         if( options_get_int("filesel_sort") ) {
314 #endif
315         if(fdp > 1)
316                 qsort((void *)lst, fdp, sizeof(struct filesel_list_item),
317                                 filenamecmp );
318
319         qsort((void *)(&lst[fdp]),
320                         FILESEL_LAST_ITEM - fdp + 1,
321                         sizeof(struct filesel_list_item),
322                         filenamecmp );
323  
324 #ifdef ABOOK_SRC
325         }
326 #endif
327 #endif
328 }        
329
330 static void
331 filesel_refresh_statusline()
332 {
333         char *p = NULL;
334         
335         move(FILESEL_STATUSLINE,0);
336         clrtoeol();
337
338         mvaddnstr(FILESEL_STATUSLINE, 5,
339                         ( p = my_getcwd() ), COLS-5 );
340
341         free(p);
342 }
343
344 static void
345 filesel_highlight_line(WINDOW *win, int line)
346 {
347         int i;
348
349         wattron(win, A_STANDOUT);
350
351         wmove(win, line, 0);
352         for(i = 0; i < FILESEL_LIST_COLS; i++)
353                 waddch(win, ' ');
354 }
355
356 static void
357 filesel_print_list_line(int i, int line)
358 {
359         if( lst[i].type == FLSL_TYPE_DIR ) {
360                 mvwaddch(filesel_list, line, 3, 'd');
361 #ifdef A_BOLD
362                 wattron(filesel_list, A_BOLD);
363 #endif
364         }
365         
366         mvwaddnstr(filesel_list, line, 5, lst[i].filename, COLS - 5);
367 }
368
369 static void
370 filesel_refresh_list()
371 {
372         int i, line;
373         
374         werase(filesel_list);
375
376         if( filesel_first_list_item < 0 || filesel_items < 1 ) {
377                 refresh();
378                 wrefresh(filesel_list);
379                 return;
380         }
381
382         for( line = 0, i = filesel_first_list_item ;
383                 i <= FILESEL_LAST_LIST_ITEM && i < filesel_items; line++, i++ ) {
384
385                 if(i == filesel_curitem) {
386                         filesel_highlight_line(filesel_list, line);
387                         wattron(filesel_list, A_STANDOUT);
388                 } else
389                         wattrset(filesel_list, 0);
390                 
391                 filesel_print_list_line(i, line);
392         }
393
394         refresh();
395         wrefresh(filesel_list);
396 }       
397
398 static void
399 filesel_scroll_up()
400 {
401         if( filesel_curitem < 1 )
402                 return;
403         filesel_curitem--;
404
405         if( filesel_first_list_item > 0 && filesel_curitem < filesel_first_list_item )
406                 filesel_first_list_item--;
407
408         filesel_refresh_list();
409 }
410
411 static void
412 filesel_scroll_down()
413 {
414         if( filesel_curitem > filesel_items - 2 )
415                 return;
416         filesel_curitem++;
417
418         if( filesel_curitem > FILESEL_LAST_LIST_ITEM )
419                 filesel_first_list_item++;
420
421         filesel_refresh_list();
422 }
423
424
425 static void
426 filesel_page_up()
427 {
428         if( filesel_curitem < 1 )
429                 return;
430         
431         if( filesel_curitem == filesel_first_list_item ) {
432                 filesel_curitem = (filesel_curitem -= FILESEL_LIST_LINES) < 0 ? 0 : filesel_curitem;
433                 filesel_first_list_item = filesel_curitem;
434         } else
435                 filesel_curitem = filesel_first_list_item;
436         
437         filesel_refresh_list();
438 }
439
440 static void
441 filesel_page_down()
442 {
443         if( filesel_curitem > filesel_items - 2 )
444                 return;
445
446         if( filesel_curitem == FILESEL_LAST_LIST_ITEM ) {
447                 filesel_curitem = (filesel_curitem += FILESEL_LIST_LINES) > FILESEL_LAST_ITEM ?
448                         FILESEL_LAST_ITEM : filesel_curitem;
449                 filesel_first_list_item = filesel_curitem - FILESEL_LIST_LINES + 1;
450                 if( filesel_first_list_item < 0 )
451                         filesel_first_list_item = 0;
452         } else
453                 filesel_curitem = FILESEL_LAST_LIST_ITEM < FILESEL_LAST_ITEM ?
454                         FILESEL_LAST_LIST_ITEM : FILESEL_LAST_ITEM;
455
456         filesel_refresh_list();
457 }
458
459
460 static void
461 filesel_goto_home()
462 {
463         if(filesel_items > 0) {
464                 filesel_first_list_item = 0;
465                 filesel_curitem = 0;
466         }
467         filesel_refresh_list();
468 }
469
470 static void
471 filesel_goto_end()
472 {
473         if(filesel_items > 0) {
474                 filesel_curitem = FILESEL_LAST_ITEM;
475                 filesel_first_list_item = filesel_curitem - FILESEL_LIST_LINES + 1;
476                 if( filesel_first_list_item < 0 )
477                         filesel_first_list_item = 0;
478         }
479         filesel_refresh_list();
480 }
481
482
483 static int
484 filesel_read_dir()
485 {
486         DIR *dir;
487         struct dirent *entry;
488         struct stat st;
489         struct filesel_list_item item;
490
491         dir = opendir(".");
492         for(;;) {
493                 entry = readdir(dir);
494                 
495                 if(entry == NULL)
496                         break;
497
498                 stat(entry->d_name, &st);
499                 strcpy(item.filename, entry->d_name);
500                 item.type = S_ISDIR(st.st_mode) ?
501                         FLSL_TYPE_DIR : FLSL_TYPE_OTHER;
502                 filesel_add_filesel_list_item(item);
503         }
504
505         closedir(dir);
506         filesel_sort_list();
507         filesel_check_list();
508         filesel_refresh_statusline();
509         filesel_refresh_list();
510         
511         return 0;
512 }
513
514 static int
515 filesel_enter()
516 {
517         char *dir, *newdir;
518
519         if(lst[filesel_curitem].type == FLSL_TYPE_DIR) {
520                 dir = my_getcwd();
521                 newdir = MALLOC(strlen(dir)+strlen(lst[filesel_curitem].filename) +2 );
522                 strcpy(newdir, dir);
523                 strcat(newdir, "/");
524                 strcat(newdir,lst[filesel_curitem].filename);
525                 free(dir);
526                 if( (chdir(newdir)) != -1) {
527                         filesel_close_list();
528                         filesel_read_dir();
529                 }
530                 free(newdir);
531                 return 0;
532         } else
533                 return 1;
534 }
535
536 static void
537 filesel_goto_item(int ch)
538 {
539         int i;
540
541         for(i=filesel_curitem+1; i<filesel_items; i++)
542                 if( lst[i].filename[0] == ch ) {
543                         filesel_curitem = i;
544                         break;
545                 }
546
547         if( filesel_curitem > FILESEL_LAST_LIST_ITEM)
548                 filesel_first_list_item=filesel_curitem;
549
550         filesel_refresh_list();
551 }
552
553
554 static int
555 filesel_loop()
556 {
557         int ch;
558         
559         for(;;) {
560                 switch( (ch = getch()) ) {
561                         case '\t':
562                         case 'q': return 1;
563                         case 'R': filesel_close_list(); filesel_read_dir();
564                                   break;
565                         case 'k':
566                         case KEY_UP: filesel_scroll_up();       break;
567                         case 'j':
568                         case KEY_DOWN: filesel_scroll_down();   break;
569                         case 'K':
570                         case KEY_PPAGE: filesel_page_up();      break;
571                         case 'J':
572                         case KEY_NPAGE: filesel_page_down();    break;
573
574                         case KEY_HOME: filesel_goto_home();     break;
575                         case KEY_END: filesel_goto_end();       break;
576
577                         case '\n':
578                         case '\r': if( filesel_enter() ) {
579                                            return 0;
580                                 }
581                                   break;
582                         default: filesel_goto_item(ch);
583                 }
584         }
585 }
586
587 char *
588 filesel()
589 {
590         char *dir, *tmp, *ptr = NULL;
591         
592         init_filesel();
593         filesel_read_dir();
594
595         if( !filesel_loop() ) {
596                 dir = my_getcwd();
597                 tmp = MALLOC(strlen(dir) + strlen(lst[filesel_curitem].filename) + 2);
598                 strcpy(tmp,dir);
599                 strcat(tmp, "/");
600                 strcat(tmp, lst[filesel_curitem].filename);
601                 ptr = strdup(tmp);
602                 free(tmp);
603                 free(dir);
604         }
605         
606         close_filesel();
607
608         return ptr;
609 }
610
611 #endif /* USE_FILESEL */
612