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