add a CVS snapshot, to thoroughly test on the Debian side
[alioth/jupp.git] / tab.c
1 /* $MirOS: contrib/code/jupp/tab.c,v 1.6 2017/01/10 19:16:28 tg Exp $ */
2 /*
3  *      File selection menu
4  *      Copyright
5  *              (C) 1992 Joseph H. Allen
6  *
7  *      This file is part of JOE (Joe's Own Editor)
8  */
9 #include "config.h"
10 #include "types.h"
11
12 #ifdef HAVE_SYS_TYPES_H
13 #include <sys/types.h>
14 #endif
15 #ifdef HAVE_SYS_STAT_H
16 #include <sys/stat.h>
17 #endif
18
19 #include <stdlib.h>
20
21 #include "b.h"
22 #include "blocks.h"
23 #include "menu.h"
24 #include "path.h"
25 #include "tty.h"
26 #include "utils.h"
27 #include "va.h"
28 #include "w.h"
29
30 typedef struct tab TAB;
31
32 extern int smode;               /* ??? */
33 extern int dobeep;
34 int menu_explorer = 0;          /* Stay in menu system when directory selected */
35
36 struct tab {
37         int first_len;                  /* Original size of path */
38         int ofst;                       /* Starting offset to path */
39         unsigned char *path;            /* current directory */
40         unsigned char *pattern;         /* search pattern */
41         int len;                /* no. entries in files */
42         unsigned char **files;          /* array of file names */
43         unsigned char **list;
44         unsigned char *type;            /* file type array */
45         int prv;
46         unsigned char *orgpath;
47         unsigned char *orgnam;
48 };
49
50 #define F_DIR           1       /* type codes for file type array */
51 #define F_NORMAL        2
52 #define F_EXEC          4
53
54 /* Read matching files from a directory
55  *  Directory is given in tab.path
56  *  Pattern is given in tab.pattern
57  *
58  * Returns with -1 if there was an error
59  * Otherwise returns index to file with inode given in prv
60  * len and files are set with the file names
61  * type is set with the file types
62  */
63
64 static int get_entries(TAB *tab, int prv)
65 {
66         int a;
67         int which = 0;
68         unsigned char *oldpwd = pwd();
69         unsigned char **files;
70
71         if (chpwd(tab->path))
72                 return -1;
73         files = rexpnd(tab->pattern);
74         if (!files) {
75                 chpwd(oldpwd);
76                 return -1;
77         }
78         if (!aLEN(files)) {
79                 chpwd(oldpwd);
80                 return -1;
81         }
82         tab->len = aLEN(files);
83         varm(tab->files);
84         tab->files = files;
85         vasort(files, tab->len);
86         if (tab->type)
87                 joe_free(tab->type);
88         tab->type = (unsigned char *) joe_malloc(tab->len);
89         for (a = 0; a != tab->len; a++) {
90                 struct stat buf;
91                 mset(&buf, 0, sizeof(struct stat));
92
93                 stat((char *)(files[a]), &buf);
94                 if ((int)buf.st_ino == prv)
95                         which = a;
96                 if ((buf.st_mode & S_IFMT) == S_IFDIR)
97                         tab->type[a] = F_DIR;
98                 else if (buf.st_mode & (0100 | 0010 | 0001))
99                         tab->type[a] = F_EXEC;
100                 else
101                         tab->type[a] = F_NORMAL;
102         }
103         chpwd(oldpwd);
104         return which;
105 }
106
107 static void insnam(BW *bw, unsigned char *path, unsigned char *nam, int dir, int ofst)
108 {
109         P *p = pdup(bw->cursor);
110
111         pgoto(p, ofst);
112         p_goto_eol(bw->cursor);
113         bdel(p, bw->cursor);
114         if (sLEN(path)) {
115                 binsm(bw->cursor, sv(path));
116                 p_goto_eol(bw->cursor);
117                 if (path[sLEN(path) - 1] != '/') {
118                         binsm(bw->cursor, sc("/"));
119                         p_goto_eol(bw->cursor);
120                 }
121         }
122         binsm(bw->cursor, sv(nam));
123         p_goto_eol(bw->cursor);
124         if (dir) {
125                 binsm(bw->cursor, sc("/"));
126                 p_goto_eol(bw->cursor);
127         }
128         prm(p);
129         bw->cursor->xcol = piscol(bw->cursor);
130 }
131
132 /* Given a menu structure with a tab structure as its object,
133  * a pattern and path set in the tab structure:
134  *
135  * Load the menu with a list of file names and set the file name in
136  * the prompt window to the directory the menu was read in from.
137  * If flg is set, treload attempts to position to the previous directory
138  * which was visited.
139  *
140  * Returns with -1 if there was an error
141  * Returns with 0 for success
142  */
143
144 static unsigned char **treload(TAB *tab,MENU *m, BW *bw, int flg,int *defer)
145 {
146         int x;
147         int which;
148         struct stat buf;
149
150         if ((which = get_entries(tab, tab->prv)) < 0)
151                 return 0;
152         if (tab->path && tab->path[0])
153                 stat((char *)tab->path, &buf);
154         else
155                 stat(".", &buf);
156         tab->prv = buf.st_ino;
157         if (!flg)
158                 which = 0;
159
160         tab->list = vatrunc(tab->list, aLEN(tab->files));
161
162         for (x = 0; tab->files[x]; ++x) {
163                 unsigned char *s = vsncpy(NULL, 0, sv(tab->files[x]));
164
165                 tab->list = vaset(tab->list, x, s);
166                 if (tab->type[x] == F_DIR)
167                         tab->list[x] = vsadd(tab->list[x], '/');
168                 else if (tab->type[x] == F_EXEC)
169                         tab->list[x] = vsadd(tab->list[x], '*');
170         }
171         if (defer) {
172                 *defer = which;
173                 insnam(bw, tab->path, tab->pattern, 0, tab->ofst);
174                 return tab->list;
175         } else {
176                 ldmenu(m, tab->list, which);
177                 insnam(bw, tab->path, tab->pattern, 0, tab->ofst);
178                 return tab->list;
179         }
180 }
181
182 static void rmtab(TAB *tab)
183 {
184         vsrm(tab->orgpath);
185         vsrm(tab->orgnam);
186         varm(tab->list);
187         vsrm(tab->path);
188         vsrm(tab->pattern);
189         varm(tab->files);
190         if (tab->type)
191                 joe_free(tab->type);
192         joe_free(tab);
193 }
194 /*****************************************************************************/
195 /****************** The user hit return **************************************/
196 /*****************************************************************************/
197 static int tabrtn(MENU *m, int cursor, TAB *tab)
198 {
199         if (menu_explorer && tab->type[cursor] == F_DIR) {      /* Switch directories */
200                 unsigned char *orgpath = tab->path;
201                 unsigned char *orgpattern = tab->pattern;
202                 unsigned char *e = endprt(tab->path);
203
204                 /* if (!strcmp(tab->files[cursor], "..") && sLEN(e)
205                     && !(e[0] == '.' && e[1] == '.' && (!e[2] || e[2] == '/')))
206                         tab->path = begprt(tab->path);
207                 else */ {
208                         tab->path = vsncpy(NULL, 0, sv(tab->path));
209                         tab->path = vsncpy(sv(tab->path), sv(m->list[cursor]));
210                 }
211                 vsrm(e);
212                 tab->pattern = vsncpy(NULL, 0, sc("*"));
213                 if (!treload(m->object, m, m->parent->win->object, 0, NULL)) {
214                         msgnw(m->parent, US "Couldn't read directory ");
215                         vsrm(tab->pattern);
216                         tab->pattern = orgpattern;
217                         vsrm(tab->path);
218                         tab->path = orgpath;
219                         return -1;
220                 } else {
221                         vsrm(orgpattern);
222                         vsrm(orgpath);
223                         return 0;
224                 }
225         } else {                /* Select name */
226                 BW *bw = m->parent->win->object;
227
228                 insnam(bw, tab->path, tab->files[cursor], (tab->type[cursor]==F_DIR), tab->ofst);
229                 rmtab(tab);
230                 m->object = NULL;
231                 m->abrt = NULL;
232                 wabort(m->parent);
233                 return 0;
234         }
235 }
236
237 /* Like above, but treats directories as files (adds them to path instead of
238  * traverse hierarchy) */
239
240 static int tabrtn1(MENU *m, int cursor, TAB *tab)
241 {
242         /* New way: just add directory to path */
243         BW *bw = m->parent->win->object;
244
245         insnam(bw, tab->path, tab->files[cursor], (tab->type[cursor]==F_DIR ? 1 : 0), tab->ofst);
246         rmtab(tab);
247         m->object = NULL;
248         m->abrt = NULL;
249         wabort(m->parent);
250         return 0;
251 }
252
253
254 /*****************************************************************************/
255 /****************** The user hit backspace ***********************************/
256 /*****************************************************************************/
257 static int tabbacks(MENU *m, int cursor, TAB *tab)
258 {
259         unsigned char *orgpath = tab->path;
260         unsigned char *orgpattern = tab->pattern;
261         unsigned char *e = endprt(tab->path);
262
263         if (sLEN(e) && sLEN(tab->path)!=tab->first_len)
264                 tab->path = begprt(tab->path);
265         else {
266                 wabort(m->parent);
267                 return 0;
268         }
269         vsrm(e);
270         tab->pattern = vsncpy(NULL, 0, sc("*"));
271
272         if (!treload(m->object, m, m->parent->win->object, 1, NULL)) {
273                 msgnw(m->parent, US "Couldn't read directory ");
274                 vsrm(tab->pattern);
275                 tab->pattern = orgpattern;
276                 vsrm(tab->path);
277                 tab->path = orgpath;
278                 return -1;
279         } else {
280                 vsrm(orgpattern);
281                 vsrm(orgpath);
282                 return 0;
283         }
284 }
285 /*****************************************************************************/
286 static int tababrt(BW *bw, int cursor, TAB *tab)
287 {
288         insnam(bw, tab->orgpath, tab->orgnam, 0, tab->ofst);
289         rmtab(tab);
290         return -1;
291 }
292
293 static void p_goto_start_of_path(P *p)
294 {
295         while (/* CONSTCOND */ 1)
296                 switch (prgetc(p)) {
297                 case '\n':
298                         pgetc(p);
299                         /* FALLTHROUGH */
300                 case NO_MORE_DATA:
301                         return;
302                 }
303 }
304
305 /*****************************************************************************/
306 /****************** Create a tab window **************************************/
307 /*****************************************************************************/
308 int cmplt(BW *bw)
309 {
310         MENU *new;
311         TAB *tab;
312         P *p, *q;
313         unsigned char *cline, *tmp;
314         long a, b;
315         int which;
316         unsigned char **l;
317         int ofst;
318
319         tab = (TAB *) joe_malloc(sizeof(TAB));
320         tab->files = NULL;
321         tab->type = NULL;
322         tab->list = NULL;
323         tab->prv = 0;
324         tab->len = 0;
325
326         q = pdup(bw->cursor);
327         p_goto_eol(q);
328         p = pdup(q);
329         p_goto_start_of_path(p);
330         ofst = p->byte;
331
332         tmp = brvs(p, (int) (q->byte - p->byte));
333         cline = parsens(tmp, &a, &b);
334         vsrm(tmp);
335         prm(p);
336         prm(q);
337
338         tab->ofst = ofst;
339         tab->pattern = namprt(cline);
340         tab->path = dirprt(cline);
341         tab->first_len = sLEN(tab->path);
342         tab->orgnam = vsncpy(NULL, 0, sv(tab->pattern));
343         tab->orgpath = vsncpy(NULL, 0, sv(tab->path));
344         tab->pattern = vsadd(tab->pattern, '*');
345         vsrm(cline);
346
347         l = treload(tab, 0, bw, 0, &which);
348
349         if (l && (new = mkmenu(bw->parent, l, tabrtn, tababrt, tabbacks, which, tab, NULL))) {
350                 if (sLEN(tab->files) == 1)
351                         return tabrtn1(new, 0, tab);
352                 else if (smode || isreg(tab->orgnam))
353                         return 0;
354                 else {
355                         unsigned char *com = mcomplete(new);
356
357                         vsrm(tab->orgnam);
358                         tab->orgnam = com;
359                         wabort(new->parent);
360                         smode = 2;
361                         /* if(dobeep) */
362                                 ttputc(7);
363                         return 0;
364                 }
365         } else {
366                 /* if(dobeep) */
367                         ttputc(7);
368                 rmtab(tab);
369                 return -1;
370         }
371 }