]> git.deb.at Git - pkg/abook.git/blob - estr.c
322f63a5fb0a1a2c01b59cb526b6395db105f7b1
[pkg/abook.git] / estr.c
1
2 /*
3  * $Id: estr.c,v 1.8 2002/01/29 11:58:13 jheinonen Exp $
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                 } 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 = 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 = REALLOC(lst, filesel_list_capacity *
262                         sizeof(struct filesel_list_item) );
263         }
264
265         lst[FILESEL_LAST_ITEM] = item;
266
267         filesel_check_list();
268         
269         return 0;
270 }
271
272
273 #define FILESEL_DIRS_FIRST
274 #define FILESEL_ALPHABETIC_ORDER
275
276 #ifdef FILESEL_ALPHABETIC_ORDER
277 #       ifndef FILESEL_DIRS_FIRST
278 #               define FILESEL_DIRS_FIRST
279 #       endif
280 #endif
281
282 #ifdef FILESEL_ALPHABETIC_ORDER
283 static int
284 filenamecmp(const void *a, const void *b)
285 {
286         return strcmp( ((struct filesel_list_item *)a) -> filename,
287                         ((struct filesel_list_item *)b) -> filename );
288 }
289 #endif
290
291 static void
292 filesel_sort_list()
293 {
294 #ifdef FILESEL_DIRS_FIRST
295         int i, j, fdp=0;
296         struct filesel_list_item tmp;
297
298         while(lst[fdp].type == FLSL_TYPE_DIR)
299                 if( ++fdp >= FILESEL_LAST_ITEM )
300                         return;
301
302         for(i = fdp + 1; i < filesel_items; i++) {
303                 if(lst[i].type == FLSL_TYPE_DIR ) {
304                         tmp = lst[fdp];
305                         lst[fdp++] = lst[i];
306                         for( j = i; j > fdp ; j--)
307                                 lst[j] = lst[j - 1];
308                         lst[fdp] = tmp;
309                 }
310         }
311 #endif
312 #ifdef FILESEL_ALPHABETIC_ORDER
313 #ifdef ABOOK_SRC
314         if( options_get_int("filesel_sort") ) {
315 #endif
316         if(fdp > 1)
317                 qsort((void *)lst, fdp, sizeof(struct filesel_list_item),
318                                 filenamecmp );
319
320         qsort((void *)(&lst[fdp]),
321                         FILESEL_LAST_ITEM - fdp + 1,
322                         sizeof(struct filesel_list_item),
323                         filenamecmp );
324  
325 #ifdef ABOOK_SRC
326         }
327 #endif
328 #endif
329 }        
330
331 static void
332 filesel_refresh_statusline()
333 {
334         char *p = NULL;
335         
336         move(FILESEL_STATUSLINE,0);
337         clrtoeol();
338
339         mvaddnstr(FILESEL_STATUSLINE, 5,
340                         ( p = my_getcwd() ), COLS-5 );
341
342         free(p);
343 }
344
345 static void
346 filesel_highlight_line(WINDOW *win, int line)
347 {
348         int i;
349
350         wattron(win, A_STANDOUT);
351
352         wmove(win, line, 0);
353         for(i = 0; i < FILESEL_LIST_COLS; i++)
354                 waddch(win, ' ');
355 }
356
357 static void
358 filesel_print_list_line(int i, int line)
359 {
360         if( lst[i].type == FLSL_TYPE_DIR ) {
361                 mvwaddch(filesel_list, line, 3, 'd');
362 #ifdef A_BOLD
363                 wattron(filesel_list, A_BOLD);
364 #endif
365         }
366         
367         mvwaddnstr(filesel_list, line, 5, lst[i].filename, COLS - 5);
368 }
369
370 static void
371 filesel_refresh_list()
372 {
373         int i, line;
374         
375         werase(filesel_list);
376
377         if( filesel_first_list_item < 0 || filesel_items < 1 ) {
378                 refresh();
379                 wrefresh(filesel_list);
380                 return;
381         }
382
383         for( line = 0, i = filesel_first_list_item ;
384                 i <= FILESEL_LAST_LIST_ITEM && i < filesel_items; line++, i++ ) {
385
386                 if(i == filesel_curitem) {
387                         filesel_highlight_line(filesel_list, line);
388                         wattron(filesel_list, A_STANDOUT);
389                 } else
390                         wattrset(filesel_list, 0);
391                 
392                 filesel_print_list_line(i, line);
393         }
394
395         refresh();
396         wrefresh(filesel_list);
397 }       
398
399 static void
400 filesel_scroll_up()
401 {
402         if( filesel_curitem < 1 )
403                 return;
404         filesel_curitem--;
405
406         if( filesel_first_list_item > 0 && filesel_curitem < filesel_first_list_item )
407                 filesel_first_list_item--;
408
409         filesel_refresh_list();
410 }
411
412 static void
413 filesel_scroll_down()
414 {
415         if( filesel_curitem > filesel_items - 2 )
416                 return;
417         filesel_curitem++;
418
419         if( filesel_curitem > FILESEL_LAST_LIST_ITEM )
420                 filesel_first_list_item++;
421
422         filesel_refresh_list();
423 }
424
425
426 static void
427 filesel_page_up()
428 {
429         if( filesel_curitem < 1 )
430                 return;
431         
432         if( filesel_curitem == filesel_first_list_item ) {
433                 filesel_curitem = (filesel_curitem -= FILESEL_LIST_LINES) < 0 ? 0 : filesel_curitem;
434                 filesel_first_list_item = filesel_curitem;
435         } else
436                 filesel_curitem = filesel_first_list_item;
437         
438         filesel_refresh_list();
439 }
440
441 static void
442 filesel_page_down()
443 {
444         if( filesel_curitem > filesel_items - 2 )
445                 return;
446
447         if( filesel_curitem == FILESEL_LAST_LIST_ITEM ) {
448                 filesel_curitem = (filesel_curitem += FILESEL_LIST_LINES) > FILESEL_LAST_ITEM ?
449                         FILESEL_LAST_ITEM : filesel_curitem;
450                 filesel_first_list_item = filesel_curitem - FILESEL_LIST_LINES + 1;
451                 if( filesel_first_list_item < 0 )
452                         filesel_first_list_item = 0;
453         } else
454                 filesel_curitem = FILESEL_LAST_LIST_ITEM < FILESEL_LAST_ITEM ?
455                         FILESEL_LAST_LIST_ITEM : FILESEL_LAST_ITEM;
456
457         filesel_refresh_list();
458 }
459
460
461 static void
462 filesel_goto_home()
463 {
464         if(filesel_items > 0) {
465                 filesel_first_list_item = 0;
466                 filesel_curitem = 0;
467         }
468         filesel_refresh_list();
469 }
470
471 static void
472 filesel_goto_end()
473 {
474         if(filesel_items > 0) {
475                 filesel_curitem = FILESEL_LAST_ITEM;
476                 filesel_first_list_item = filesel_curitem - FILESEL_LIST_LINES + 1;
477                 if( filesel_first_list_item < 0 )
478                         filesel_first_list_item = 0;
479         }
480         filesel_refresh_list();
481 }
482
483
484 static int
485 filesel_read_dir()
486 {
487         DIR *dir;
488         struct dirent *entry;
489         struct stat st;
490         struct filesel_list_item item;
491
492         dir = opendir(".");
493         for(;;) {
494                 entry = readdir(dir);
495                 
496                 if(entry == NULL)
497                         break;
498
499                 stat(entry->d_name, &st);
500                 strcpy(item.filename, entry->d_name);
501                 item.type = S_ISDIR(st.st_mode) ?
502                         FLSL_TYPE_DIR : FLSL_TYPE_OTHER;
503                 filesel_add_filesel_list_item(item);
504         }
505
506         closedir(dir);
507         filesel_sort_list();
508         filesel_check_list();
509         filesel_refresh_statusline();
510         filesel_refresh_list();
511         
512         return 0;
513 }
514
515 static int
516 filesel_enter()
517 {
518         char *dir, *newdir;
519
520         if(lst[filesel_curitem].type == FLSL_TYPE_DIR) {
521                 dir = my_getcwd();
522                 newdir = MALLOC(strlen(dir)+strlen(lst[filesel_curitem].filename) +2 );
523                 strcpy(newdir, dir);
524                 strcat(newdir, "/");
525                 strcat(newdir,lst[filesel_curitem].filename);
526                 free(dir);
527                 if( (chdir(newdir)) != -1) {
528                         filesel_close_list();
529                         filesel_read_dir();
530                 }
531                 free(newdir);
532                 return 0;
533         } else
534                 return 1;
535 }
536
537 static void
538 filesel_goto_item(int ch)
539 {
540         int i;
541
542         for(i=filesel_curitem+1; i<filesel_items; i++)
543                 if( lst[i].filename[0] == ch ) {
544                         filesel_curitem = i;
545                         break;
546                 }
547
548         if( filesel_curitem > FILESEL_LAST_LIST_ITEM)
549                 filesel_first_list_item=filesel_curitem;
550
551         filesel_refresh_list();
552 }
553
554
555 static int
556 filesel_loop()
557 {
558         int ch;
559         
560         for(;;) {
561                 switch( (ch = getch()) ) {
562                         case '\t':
563                         case 'q': return 1;
564                         case 'R': filesel_close_list(); filesel_read_dir();
565                                   break;
566                         case 'k':
567                         case KEY_UP: filesel_scroll_up();       break;
568                         case 'j':
569                         case KEY_DOWN: filesel_scroll_down();   break;
570                         case 'K':
571                         case KEY_PPAGE: filesel_page_up();      break;
572                         case 'J':
573                         case KEY_NPAGE: filesel_page_down();    break;
574
575                         case KEY_HOME: filesel_goto_home();     break;
576                         case KEY_END: filesel_goto_end();       break;
577
578                         case '\n':
579                         case '\r': if( filesel_enter() ) {
580                                            return 0;
581                                 }
582                                   break;
583                         default: filesel_goto_item(ch);
584                 }
585         }
586 }
587
588 char *
589 filesel()
590 {
591         char *dir, *tmp, *ptr = NULL;
592         
593         init_filesel();
594         filesel_read_dir();
595
596         if( !filesel_loop() ) {
597                 dir = my_getcwd();
598                 tmp = MALLOC(strlen(dir) + strlen(lst[filesel_curitem].filename) + 2);
599                 strcpy(tmp,dir);
600                 strcat(tmp, "/");
601                 strcat(tmp, lst[filesel_curitem].filename);
602                 ptr = strdup(tmp);
603                 free(tmp);
604                 free(dir);
605         }
606         
607         close_filesel();
608
609         return ptr;
610 }
611
612 #endif /* USE_FILESEL */
613