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