]> git.deb.at Git - pkg/abook.git/blob - estr.c
Ids added
[pkg/abook.git] / estr.c
1
2 /*
3  * $Id$
4  *  
5  * by JH <jheinonen@bigfoot.com>
6  *
7  * Copyright (C) Jaakko Heinonen
8  *
9  */
10
11
12 #define USE_FILESEL     1
13 /*#undef USE_FILESEL*/
14
15 #define ABOOK_SRC       1
16 /*#undef ABOOK_SRC*/
17
18 #include <stdlib.h>
19 #include <ctype.h>
20 #include <string.h>
21 #ifdef ABOOK_SRC
22 #       include "abook_curses.h"
23 #       include "options.h"
24 #else
25 #       include <ncurses.h>
26 #endif
27 #ifdef HAVE_CONFIG_H
28 #       include "config.h"
29 #endif
30 #include "estr.h"
31
32 #if defined(HAVE_LOCALE_H) || defined(HAVE_SETLOCALE)
33 #       include <locale.h>
34 #else
35 /*
36  * this is a quick and dirty hack and it is
37  * not likely to work well
38  */
39 #       undef iscntrl
40 #       undef isprint
41 #       define iscntrl(X)       (X < 32)
42 #       define isprint(X)       (!iscntrl(X))
43 #endif
44
45 /*
46  * hmmm, these should be universal and nice :)
47  */
48
49 #define         XCTRL(x) ((x) & 31)
50
51 #define         ENTER_KEY       KEY_ENTER
52 #define         BACKSPACE_KEY   KEY_BACKSPACE
53 #define         CANCEL_KEY      XCTRL('g')
54 #define         TAB_KEY         '\t'
55
56 #ifdef ABOOK_SRC
57 #       include "abook.h"
58 #       define MALLOC(X)        abook_malloc(X)
59 #       define REALLOC(X, XX)   abook_realloc(X, XX)
60 #else
61 #       define MALLOC(X)        malloc(X)
62 #       define REALLOC(X, XX)   realloc(X, XX)
63 #endif
64
65 /* introduce filesel */
66 #ifdef USE_FILESEL
67 char            *filesel();
68 #endif
69
70 #define INITIAL_BUFSIZE         100
71
72 char *
73 wenter_string(WINDOW *win, const int maxlen, const int flags)
74 {
75         int i = 0;
76         int y, x;
77         int ch;
78         char *str = NULL;
79         int size = maxlen > 0 ? maxlen + 1 : INITIAL_BUFSIZE; 
80
81         getyx(win, y, x);
82         str = MALLOC(size);
83
84         for( ;; ) { /* main loop */
85                 if(flags & ESTR_DONT_WRAP && x+i>COLS-2) {
86                         mvwaddnstr(win, y, x, str+(1+x+i-COLS), COLS-x-1);
87                         wmove(win, y, COLS-1);
88                         wclrtoeol(win);
89                 } else
90                         wmove(win, y, x + i);
91
92                 wrefresh(win);
93
94                 switch( (ch = getch()) ) {
95                         case ENTER_KEY:
96                         case 10:
97                         case 13:
98                                 goto out;
99                         case BACKSPACE_KEY:
100                         case 127:
101                                 if(i > 0)
102                                         mvwdelch(win, y, x + --i);
103                                 continue;       
104                         case CANCEL_KEY:
105                                 free(str);
106                                 return NULL;
107 #ifdef USE_FILESEL
108                         case TAB_KEY:
109                                 if( ! (flags & ESTR_USE_FILESEL) )
110                                         continue;
111                                 i = -1;
112                                 free(str);
113                                 str = filesel();
114                                 goto out;
115 #endif
116                 }
117                 if( !isprint(ch) || iscntrl(ch)
118                         || (maxlen > 0 && i + 1 > maxlen) )
119                         continue;
120                 str[i++] = ch;
121                 waddch(win,ch);
122                 if( i + 1 > size )
123                         str = REALLOC( str, size *= 2 );
124                 if( maxlen > 0 && i > maxlen)
125                         break;
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@bigfoot.com>
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 * sizeof(struct filesel_list_item),
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                 wattron(filesel_list, A_BOLD);
362         
363         mvwaddnstr(filesel_list, line, 5, lst[i].filename, COLS - 5);
364 }
365
366 static void
367 filesel_refresh_list()
368 {
369         int i, line;
370         
371         werase(filesel_list);
372
373         if( filesel_first_list_item < 0 || filesel_items < 1 ) {
374                 refresh();
375                 wrefresh(filesel_list);
376                 return;
377         }
378
379         for( line = 0, i = filesel_first_list_item ;
380                 i <= FILESEL_LAST_LIST_ITEM && i < filesel_items; line++, i++ ) {
381
382                 if(i == filesel_curitem) {
383                         filesel_highlight_line(filesel_list, line);
384                         wattron(filesel_list, A_STANDOUT);
385                 } else
386                         wattrset(filesel_list, 0);
387                 
388                 filesel_print_list_line(i, line);
389         }
390
391         refresh();
392         wrefresh(filesel_list);
393 }       
394
395 static void
396 filesel_scroll_up()
397 {
398         if( filesel_curitem < 1 )
399                 return;
400         filesel_curitem--;
401
402         if( filesel_first_list_item > 0 && filesel_curitem < filesel_first_list_item )
403                 filesel_first_list_item--;
404
405         filesel_refresh_list();
406 }
407
408 static void
409 filesel_scroll_down()
410 {
411         if( filesel_curitem > filesel_items - 2 )
412                 return;
413         filesel_curitem++;
414
415         if( filesel_curitem > FILESEL_LAST_LIST_ITEM )
416                 filesel_first_list_item++;
417
418         filesel_refresh_list();
419 }
420
421
422 static void
423 filesel_page_up()
424 {
425         if( filesel_curitem < 1 )
426                 return;
427         
428         if( filesel_curitem == filesel_first_list_item ) {
429                 filesel_curitem = (filesel_curitem -= FILESEL_LIST_LINES) < 0 ? 0 : filesel_curitem;
430                 filesel_first_list_item = filesel_curitem;
431         } else
432                 filesel_curitem = filesel_first_list_item;
433         
434         filesel_refresh_list();
435 }
436
437 static void
438 filesel_page_down()
439 {
440         if( filesel_curitem > filesel_items - 2 )
441                 return;
442
443         if( filesel_curitem == FILESEL_LAST_LIST_ITEM ) {
444                 filesel_curitem = (filesel_curitem += FILESEL_LIST_LINES) > FILESEL_LAST_ITEM ?
445                         FILESEL_LAST_ITEM : filesel_curitem;
446                 filesel_first_list_item = filesel_curitem - FILESEL_LIST_LINES + 1;
447                 if( filesel_first_list_item < 0 )
448                         filesel_first_list_item = 0;
449         } else
450                 filesel_curitem = FILESEL_LAST_LIST_ITEM < FILESEL_LAST_ITEM ?
451                         FILESEL_LAST_LIST_ITEM : FILESEL_LAST_ITEM;
452
453         filesel_refresh_list();
454 }
455
456
457 static void
458 filesel_goto_home()
459 {
460         if(filesel_items > 0) {
461                 filesel_first_list_item = 0;
462                 filesel_curitem = 0;
463         }
464         filesel_refresh_list();
465 }
466
467 static void
468 filesel_goto_end()
469 {
470         if(filesel_items > 0) {
471                 filesel_curitem = FILESEL_LAST_ITEM;
472                 filesel_first_list_item = filesel_curitem - FILESEL_LIST_LINES + 1;
473                 if( filesel_first_list_item < 0 )
474                         filesel_first_list_item = 0;
475         }
476         filesel_refresh_list();
477 }
478
479
480 static int
481 filesel_read_dir()
482 {
483         DIR *dir;
484         struct dirent *entry;
485         struct stat st;
486         struct filesel_list_item item;
487
488         dir = opendir(".");
489         for(;;) {
490                 entry = readdir(dir);
491                 
492                 if(entry == NULL)
493                         break;
494
495                 stat(entry->d_name, &st);
496                 strcpy(item.filename, entry->d_name);
497                 item.type = S_ISDIR(st.st_mode) ?
498                         FLSL_TYPE_DIR : FLSL_TYPE_OTHER;
499                 filesel_add_filesel_list_item(item);
500         }
501
502         closedir(dir);
503         filesel_sort_list();
504         filesel_check_list();
505         filesel_refresh_statusline();
506         filesel_refresh_list();
507         
508         return 0;
509 }
510
511 static int
512 filesel_enter()
513 {
514         char *dir, *newdir;
515
516         if(lst[filesel_curitem].type == FLSL_TYPE_DIR) {
517                 dir = my_getcwd();
518                 newdir = MALLOC(strlen(dir)+strlen(lst[filesel_curitem].filename) +2 );
519                 strcpy(newdir, dir);
520                 strcat(newdir, "/");
521                 strcat(newdir,lst[filesel_curitem].filename);
522                 free(dir);
523                 if( (chdir(newdir)) != -1) {
524                         filesel_close_list();
525                         filesel_read_dir();
526                 }
527                 free(newdir);
528                 return 0;
529         } else
530                 return 1;
531 }
532
533 static void
534 filesel_goto_item(int ch)
535 {
536         int i;
537
538         for(i=filesel_curitem+1; i<filesel_items; i++)
539                 if( lst[i].filename[0] == ch ) {
540                         filesel_curitem = i;
541                         break;
542                 }
543
544         if( filesel_curitem > FILESEL_LAST_LIST_ITEM)
545                 filesel_first_list_item=filesel_curitem;
546
547         filesel_refresh_list();
548 }
549
550
551 static int
552 filesel_loop()
553 {
554         int ch;
555         
556         for(;;) {
557                 switch( (ch = getch()) ) {
558                         case '\t':
559                         case 'q': return 1;
560                         case 'R': filesel_close_list(); filesel_read_dir();
561                                   break;
562                         case 'k':
563                         case KEY_UP: filesel_scroll_up();       break;
564                         case 'j':
565                         case KEY_DOWN: filesel_scroll_down();   break;
566                         case 'K':
567                         case KEY_PPAGE: filesel_page_up();      break;
568                         case 'J':
569                         case KEY_NPAGE: filesel_page_down();    break;
570
571                         case KEY_HOME: filesel_goto_home();     break;
572                         case KEY_END: filesel_goto_end();       break;
573
574                         case '\n':
575                         case '\r': if( filesel_enter() ) {
576                                            return 0;
577                                 }
578                                   break;
579                         default: filesel_goto_item(ch);
580                 }
581         }
582 }
583
584 char *
585 filesel()
586 {
587         char *dir, *tmp, *ptr = NULL;
588         
589         init_filesel();
590         filesel_read_dir();
591
592         if( !filesel_loop() ) {
593                 dir = my_getcwd();
594                 tmp = MALLOC(strlen(dir) + strlen(lst[filesel_curitem].filename) + 2);
595                 strcpy(tmp,dir);
596                 strcat(tmp, "/");
597                 strcat(tmp, lst[filesel_curitem].filename);
598                 ptr = strdup(tmp);
599                 free(tmp);
600                 free(dir);
601         }
602         
603         close_filesel();
604
605         return ptr;
606 }
607
608 #endif /* USE_FILESEL */
609