another update from CVS HEAD, for QA
[alioth/jupp.git] / ushell.c
1 /*
2  *      Shell-window functions
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/ushell.c,v 1.15 2017/12/08 03:24:16 tg Exp $");
12
13 #include <sys/stat.h>
14 #include <signal.h>
15 #include <stdlib.h>
16 #include <unistd.h>
17
18 #include "b.h"
19 #include "main.h"
20 #include "pw.h"
21 #include "qw.h"
22 #include "tty.h"
23 #include "uedit.h"
24 #include "uerror.h"
25 #include "ufile.h"
26 #include "va.h"
27 #include "vs.h"
28 #include "ushell.h"
29 #include "utf8.h"
30 #include "w.h"
31
32 extern int orphan;
33
34 #if WANT_FORK
35 /* Executed when shell process terminates */
36
37 static void cdone(B *b)
38 {
39         b->pid = 0;
40         close(b->out);
41         b->out = -1;
42 }
43
44 static void cdone_parse(B *b)
45 {
46         b->pid = 0;
47         close(b->out);
48         b->out = -1;
49         parserrb(b);
50 }
51
52 /* Executed for each chunk of data we get from the shell */
53
54 static void cfollow(B *b,long byte)
55 {
56         W *w;
57         if ((w = maint->topwin) != NULL) {
58                 do {
59                         if ((w->watom->what & TYPETW) &&
60                             w->object.bw->b == b &&
61                             w->object.bw->cursor->byte == byte) {
62                                 BW *bw = w->object.bw;
63                                 p_goto_eof(bw->cursor);
64                                 bw->cursor->xcol = piscol(bw->cursor);
65                         }
66                         w = w->link.next;
67                 } while (w != maint->topwin);
68         }
69 }
70
71 static void cdata(B *b, unsigned char *dat, int siz)
72 {
73         P *q = pdup(b->eof);
74         P *r = pdup(b->eof);
75         long byte = q->byte;
76         unsigned char bf[1024];
77         int x, y;
78
79         for (x = y = 0; x != siz; ++x) {
80                 if (dat[x] == 13 || dat[x] == 0) {
81                         ;
82                 } else if (dat[x] == 8 || dat[x] == 127) {
83                         if (y) {
84                                 --y;
85                         } else {
86                                 pset(q, r);
87                                 prgetc(q);
88                                 bdel(q, r);
89                                 --byte;
90                         }
91                 } else if (dat[x] == 7) {
92                         ttputc(7);
93                 } else {
94                         bf[y++] = dat[x];
95                 }
96         }
97         if (y) {
98                 binsm(r, bf, y);
99         }
100         prm(r);
101         prm(q);
102
103         cfollow(b,byte);
104 }
105
106 static int doushell(BW *bw, unsigned char *cmd, int *notify, int build)
107 {
108         MPX *m;
109         unsigned char **s;
110         unsigned char *u;
111         const unsigned char *name;
112
113         name = getushell();
114         s = vamk(10);
115         u = vsncpy(NULL, 0, sz(name));
116         s = vaadd(s, u);
117         if (cmd) {
118                 u = vsncpy(NULL, 0, sc("-c"));
119                 s = vaadd(s, u);
120                 s = vaadd(s, cmd);
121         } else {
122                 u = vsncpy(NULL, 0, sc("-i"));
123                 s = vaadd(s, u);
124         }
125
126         if (notify) {
127                 *notify = 1;
128         }
129         if (bw->b->pid) {
130                 msgnw(bw->parent, UC "Program already running in this window");
131                 varm(s);
132                 vsrm(cmd);
133                 return -1;
134         }
135         p_goto_eof(bw->cursor);
136
137         if (!(m = mpxmk(&bw->b->out, name, s, cdata, bw->b, build ? cdone_parse : cdone, bw->b))) {
138                 varm(s);
139                 vsrm(cmd);
140                 msgnw(bw->parent, UC "No ptys available");
141                 return -1;
142         } else {
143                 bw->b->pid = m->pid;
144         }
145         varm(s);
146         vsrm(cmd);
147         return 0;
148 }
149
150 int ubknd(BW *bw)
151 {
152         if (!getenv("SHELL")) {
153                 msgnw(bw->parent, UC "\"SHELL\" environment variable not defined or exported");
154         }
155         return doushell(bw, NULL, NULL, 0);
156 }
157
158 /* Run a program in a window */
159
160 static int dorun(BW *bw, unsigned char *s, void *object, int *notify)
161 {
162         return doushell(bw, s, notify, 0);
163 }
164
165 B *runhist = NULL;
166
167 int urun(BW *bw)
168 {
169         if (wmkpw(bw->parent, UC "Program to run: ", &runhist, dorun, UC "Run", NULL, NULL, NULL, NULL, locale_map)) {
170                 return 0;
171         } else {
172                 return -1;
173         }
174 }
175
176 static int dobuild(BW *bw, unsigned char *s, void *object, int *notify)
177 {
178         return doushell(bw, s, notify, 1);
179 }
180
181 B *buildhist = NULL;
182
183 int ubuild(BW *bw)
184 {
185         if (buildhist) {
186                 if ((bw=wmkpw(bw->parent, UC "Build command: ", &buildhist, dobuild, UC "Run", NULL, NULL, NULL, NULL, locale_map))) {
187                         uuparw(bw);
188                         u_goto_eol(bw);
189                         bw->cursor->xcol = piscol(bw->cursor);
190                         return 0;
191                 }
192         } else if (wmkpw(bw->parent, UC "Enter build command (for example, 'make'): ", &buildhist, dobuild, UC "Run", NULL, NULL, NULL, NULL, locale_map))
193                         return 0;
194                 return -1;
195 }
196 #endif
197
198 /* Kill program */
199
200 static int pidabort(BW *bw, int c, void *object, int *notify)
201 {
202         if (notify) {
203                 *notify = 1;
204         }
205         if ((c | 0x20) != 'y') {
206                 return -1;
207         }
208         if (bw->b->pid) {
209                 kill(bw->b->pid, 1);
210                 return -1;
211         } else {
212                 return -1;
213         }
214 }
215
216 int ukillpid(BW *bw)
217 {
218         if (bw->b->pid) {
219                 if (mkqw(bw->parent, sc("Kill program (y,n,^C)?"), pidabort, NULL, NULL, NULL)) {
220                         return 0;
221                 } else {
222                         return -1;
223                 }
224         } else {
225                 return 0;
226         }
227 }
228
229 static const char * const getushell_envs[] = {
230         "SHELL",
231         "EXECSHELL",
232 };
233 const void *getushell(void)
234 {
235         static char *rshell;
236
237         if (!rshell) {
238                 char *eshell;
239                 struct stat sbuf;
240                 int i = 0;
241
242                 while (i < 2) {
243                         eshell = getenv(getushell_envs[i++]);
244                         if (eshell && *eshell &&
245                             !stat(eshell, &sbuf) &&
246                             S_ISREG(sbuf.st_mode) &&
247                             (sbuf.st_mode & 0111) &&
248                             /* LINTED use of access */
249                             !access(eshell, X_OK)) {
250                                 rshell = eshell;
251                                 break;
252                         }
253                 }
254         }
255         return (rshell ? rshell : "/bin/sh");
256 }