]> git.deb.at Git - pkg/abook.git/blob - estr.c
use_ascii_only configuration option
[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 #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@bigfoot.com>
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 * sizeof(struct filesel_list_item),
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                 wattron(filesel_list, A_BOLD);
361         
362         mvwaddnstr(filesel_list, line, 5, lst[i].filename, COLS - 5);
363 }
364
365 static void
366 filesel_refresh_list()
367 {
368         int i, line;
369         
370         werase(filesel_list);
371
372         if( filesel_first_list_item < 0 || filesel_items < 1 ) {
373                 refresh();
374                 wrefresh(filesel_list);
375                 return;
376         }
377
378         for( line = 0, i = filesel_first_list_item ;
379                 i <= FILESEL_LAST_LIST_ITEM && i < filesel_items; line++, i++ ) {
380
381                 if(i == filesel_curitem) {
382                         filesel_highlight_line(filesel_list, line);
383                         wattron(filesel_list, A_STANDOUT);
384                 } else
385                         wattrset(filesel_list, 0);
386                 
387                 filesel_print_list_line(i, line);
388         }
389
390         refresh();
391         wrefresh(filesel_list);
392 }       
393
394 static void
395 filesel_scroll_up()
396 {
397         if( filesel_curitem < 1 )
398                 return;
399         filesel_curitem--;
400
401         if( filesel_first_list_item > 0 && filesel_curitem < filesel_first_list_item )
402                 filesel_first_list_item--;
403
404         filesel_refresh_list();
405 }
406
407 static void
408 filesel_scroll_down()
409 {
410         if( filesel_curitem > filesel_items - 2 )
411                 return;
412         filesel_curitem++;
413
414         if( filesel_curitem > FILESEL_LAST_LIST_ITEM )
415                 filesel_first_list_item++;
416
417         filesel_refresh_list();
418 }
419
420
421 static void
422 filesel_page_up()
423 {
424         if( filesel_curitem < 1 )
425                 return;
426         
427         if( filesel_curitem == filesel_first_list_item ) {
428                 filesel_curitem = (filesel_curitem -= FILESEL_LIST_LINES) < 0 ? 0 : filesel_curitem;
429                 filesel_first_list_item = filesel_curitem;
430         } else
431                 filesel_curitem = filesel_first_list_item;
432         
433         filesel_refresh_list();
434 }
435
436 static void
437 filesel_page_down()
438 {
439         if( filesel_curitem > filesel_items - 2 )
440                 return;
441
442         if( filesel_curitem == FILESEL_LAST_LIST_ITEM ) {
443                 filesel_curitem = (filesel_curitem += FILESEL_LIST_LINES) > FILESEL_LAST_ITEM ?
444                         FILESEL_LAST_ITEM : filesel_curitem;
445                 filesel_first_list_item = filesel_curitem - FILESEL_LIST_LINES + 1;
446                 if( filesel_first_list_item < 0 )
447                         filesel_first_list_item = 0;
448         } else
449                 filesel_curitem = FILESEL_LAST_LIST_ITEM < FILESEL_LAST_ITEM ?
450                         FILESEL_LAST_LIST_ITEM : FILESEL_LAST_ITEM;
451
452         filesel_refresh_list();
453 }
454
455
456 static void
457 filesel_goto_home()
458 {
459         if(filesel_items > 0) {
460                 filesel_first_list_item = 0;
461                 filesel_curitem = 0;
462         }
463         filesel_refresh_list();
464 }
465
466 static void
467 filesel_goto_end()
468 {
469         if(filesel_items > 0) {
470                 filesel_curitem = FILESEL_LAST_ITEM;
471                 filesel_first_list_item = filesel_curitem - FILESEL_LIST_LINES + 1;
472                 if( filesel_first_list_item < 0 )
473                         filesel_first_list_item = 0;
474         }
475         filesel_refresh_list();
476 }
477
478
479 static int
480 filesel_read_dir()
481 {
482         DIR *dir;
483         struct dirent *entry;
484         struct stat st;
485         struct filesel_list_item item;
486
487         dir = opendir(".");
488         for(;;) {
489                 entry = readdir(dir);
490                 
491                 if(entry == NULL)
492                         break;
493
494                 stat(entry->d_name, &st);
495                 strcpy(item.filename, entry->d_name);
496                 item.type = S_ISDIR(st.st_mode) ?
497                         FLSL_TYPE_DIR : FLSL_TYPE_OTHER;
498                 filesel_add_filesel_list_item(item);
499         }
500
501         closedir(dir);
502         filesel_sort_list();
503         filesel_check_list();
504         filesel_refresh_statusline();
505         filesel_refresh_list();
506         
507         return 0;
508 }
509
510 static int
511 filesel_enter()
512 {
513         char *dir, *newdir;
514
515         if(lst[filesel_curitem].type == FLSL_TYPE_DIR) {
516                 dir = my_getcwd();
517                 newdir = MALLOC(strlen(dir)+strlen(lst[filesel_curitem].filename) +2 );
518                 strcpy(newdir, dir);
519                 strcat(newdir, "/");
520                 strcat(newdir,lst[filesel_curitem].filename);
521                 free(dir);
522                 if( (chdir(newdir)) != -1) {
523                         filesel_close_list();
524                         filesel_read_dir();
525                 }
526                 free(newdir);
527                 return 0;
528         } else
529                 return 1;
530 }
531
532 static void
533 filesel_goto_item(int ch)
534 {
535         int i;
536
537         for(i=filesel_curitem+1; i<filesel_items; i++)
538                 if( lst[i].filename[0] == ch ) {
539                         filesel_curitem = i;
540                         break;
541                 }
542
543         if( filesel_curitem > FILESEL_LAST_LIST_ITEM)
544                 filesel_first_list_item=filesel_curitem;
545
546         filesel_refresh_list();
547 }
548
549
550 static int
551 filesel_loop()
552 {
553         int ch;
554         
555         for(;;) {
556                 switch( (ch = getch()) ) {
557                         case '\t':
558                         case 'q': return 1;
559                         case 'R': filesel_close_list(); filesel_read_dir();
560                                   break;
561                         case 'k':
562                         case KEY_UP: filesel_scroll_up();       break;
563                         case 'j':
564                         case KEY_DOWN: filesel_scroll_down();   break;
565                         case 'K':
566                         case KEY_PPAGE: filesel_page_up();      break;
567                         case 'J':
568                         case KEY_NPAGE: filesel_page_down();    break;
569
570                         case KEY_HOME: filesel_goto_home();     break;
571                         case KEY_END: filesel_goto_end();       break;
572
573                         case '\n':
574                         case '\r': if( filesel_enter() ) {
575                                            return 0;
576                                 }
577                                   break;
578                         default: filesel_goto_item(ch);
579                 }
580         }
581 }
582
583 char *
584 filesel()
585 {
586         char *dir, *tmp, *ptr = NULL;
587         
588         init_filesel();
589         filesel_read_dir();
590
591         if( !filesel_loop() ) {
592                 dir = my_getcwd();
593                 tmp = MALLOC(strlen(dir) + strlen(lst[filesel_curitem].filename) + 2);
594                 strcpy(tmp,dir);
595                 strcat(tmp, "/");
596                 strcat(tmp, lst[filesel_curitem].filename);
597                 ptr = strdup(tmp);
598                 free(tmp);
599                 free(dir);
600         }
601         
602         close_filesel();
603
604         return ptr;
605 }
606
607 #endif /* USE_FILESEL */
608