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