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