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