we’ll need to distinguish these for sarge/etch as well
[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.8 2017/12/02 02:07:36 tg Exp $");
12
13 #include <unistd.h>
14 #ifdef HAVE_SYS_STAT_H
15 #include <sys/stat.h>
16 #endif
17 #ifdef HAVE_SIGNAL_H
18 #include <signal.h>
19 #endif
20 #ifdef HAVE_STDLIB_H
21 #include <stdlib.h>
22 #endif
23
24 #include "b.h"
25 #include "main.h"
26 #include "pw.h"
27 #include "qw.h"
28 #include "tty.h"
29 #include "uedit.h"
30 #include "uerror.h"
31 #include "ufile.h"
32 #include "va.h"
33 #include "vs.h"
34 #include "ushell.h"
35 #include "utf8.h"
36 #include "w.h"
37
38 extern int orphan;
39
40 #if WANT_FORK
41 /* Executed when shell process terminates */
42
43 static void cdone(B *b)
44 {
45         b->pid = 0;
46         close(b->out);
47         b->out = -1;
48 }
49
50 static void cdone_parse(B *b)
51 {
52         b->pid = 0;
53         close(b->out);
54         b->out = -1;
55         parserrb(b);
56 }
57
58 /* Executed for each chunk of data we get from the shell */
59
60 static void cfollow(B *b,long byte)
61 {
62         W *w;
63          if ((w = maint->topwin) != NULL) {
64                 do {
65                         if ((w->watom->what&TYPETW) && ((BW *)w->object)->b==b && ((BW *)w->object)->cursor->byte==byte) {
66                                 BW *bw = (BW *)w->object;
67                                 p_goto_eof(bw->cursor);
68                                 bw->cursor->xcol = piscol(bw->cursor);
69                         }
70                 w = w->link.next;
71                 } while (w != maint->topwin);
72          }
73 }
74
75 static void cdata(B *b, unsigned char *dat, int siz)
76 {
77         P *q = pdup(b->eof);
78         P *r = pdup(b->eof);
79         long byte = q->byte;
80         unsigned char bf[1024];
81         int x, y;
82
83         for (x = y = 0; x != siz; ++x) {
84                 if (dat[x] == 13 || dat[x] == 0) {
85                         ;
86                 } else if (dat[x] == 8 || dat[x] == 127) {
87                         if (y) {
88                                 --y;
89                         } else {
90                                 pset(q, r);
91                                 prgetc(q);
92                                 bdel(q, r);
93                                 --byte;
94                         }
95                 } else if (dat[x] == 7) {
96                         ttputc(7);
97                 } else {
98                         bf[y++] = dat[x];
99                 }
100         }
101         if (y) {
102                 binsm(r, bf, y);
103         }
104         prm(r);
105         prm(q);
106
107         cfollow(b,byte);
108 }
109
110 static int doushell(BW *bw, unsigned char *cmd, int *notify, int build)
111 {
112         MPX *m;
113         unsigned char **s;
114         unsigned char *u;
115         const unsigned char *name;
116
117         name = getushell();
118         s = vamk(10);
119         u = vsncpy(NULL, 0, sz(name));
120         s = vaadd(s, u);
121         if (cmd) {
122                 u = vsncpy(NULL, 0, sc("-c"));
123                 s = vaadd(s, u);
124                 s = vaadd(s, cmd);
125         } else {
126                 u = vsncpy(NULL, 0, sc("-i"));
127                 s = vaadd(s, u);
128         }
129
130         if (notify) {
131                 *notify = 1;
132         }
133         if (bw->b->pid) {
134                 msgnw(bw->parent, US "Program already running in this window");
135                 varm(s);
136                 return -1;
137         }
138         p_goto_eof(bw->cursor);
139
140         if (!(m = mpxmk(&bw->b->out, name, s, cdata, bw->b, build ? cdone_parse : cdone, bw->b))) {
141                 varm(s);
142                 msgnw(bw->parent, US "No ptys available");
143                 return -1;
144         } else {
145                 bw->b->pid = m->pid;
146         }
147         return 0;
148 }
149
150 int ubknd(BW *bw)
151 {
152         if (!getenv("SHELL")) {
153                 msgnw(bw->parent, US "\"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, US "Program to run: ", &runhist, dorun, US "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, US "Build command: ", &buildhist, dobuild, US "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, US "Enter build command (for example, 'make'): ", &buildhist, dobuild, US "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 != 'y' && c != '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 }