This repository has been archived by the owner on Jul 13, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathaproc.c
131 lines (119 loc) · 3.67 KB
/
aproc.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
#include <stdio.h>
#include <stdarg.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <fcntl.h>
#include <signal.h>
#include <utlist.h>
#include "mle.h"
// Return a new aproc_t
aproc_t *aproc_new(editor_t *editor, void *owner, aproc_t **owner_aproc, char *shell_cmd, int rw, aproc_cb_t callback) {
aproc_t *aproc;
aproc = calloc(1, sizeof(aproc_t));
aproc->editor = editor;
aproc_set_owner(aproc, owner, owner_aproc);
if (rw) {
if (!util_popen2(shell_cmd, 0, NULL, &aproc->rfd, &aproc->wfd, &aproc->pid)) {
goto aproc_new_failure;
}
aproc->rpipe = fdopen(aproc->rfd, "r");
aproc->wpipe = fdopen(aproc->wfd, "w");
} else {
if (!(aproc->rpipe = popen(shell_cmd, "r"))) {
goto aproc_new_failure;
}
aproc->rfd = fileno(aproc->rpipe);
}
setvbuf(aproc->rpipe, NULL, _IONBF, 0);
if (aproc->wpipe) setvbuf(aproc->wpipe, NULL, _IONBF, 0);
aproc->callback = callback;
DL_APPEND(editor->aprocs, aproc);
return aproc;
aproc_new_failure:
free(aproc);
return NULL;
}
// Set aproc owner
int aproc_set_owner(aproc_t *aproc, void *owner, aproc_t **owner_aproc) {
if (aproc->owner_aproc) {
*aproc->owner_aproc = NULL;
}
*owner_aproc = aproc;
aproc->owner = owner;
aproc->owner_aproc = owner_aproc;
return MLE_OK;
}
// Destroy an aproc_t
int aproc_destroy(aproc_t *aproc, int preempt) {
DL_DELETE(aproc->editor->aprocs, aproc);
if (aproc->owner_aproc) *aproc->owner_aproc = NULL;
if (preempt) {
if (aproc->rfd) close(aproc->rfd);
if (aproc->wfd) close(aproc->wfd);
if (aproc->pid) kill(aproc->pid, SIGTERM);
}
if (aproc->rpipe) pclose(aproc->rpipe);
if (aproc->wpipe) pclose(aproc->wpipe);
free(aproc);
return MLE_OK;
}
// Manage async procs, giving priority to user input. Return 1 if drain should
// be called again, else return 0.
int aproc_drain_all(aproc_t *aprocs, int *ttyfd) {
int maxfd;
fd_set readfds;
aproc_t *aproc;
aproc_t *aproc_tmp;
char buf[1024 + 1];
ssize_t nbytes;
int rc;
// Exit early if no aprocs
if (!aprocs) return 0;
// Open ttyfd if not already open
if (!*ttyfd) {
if ((*ttyfd = open("/dev/tty", O_RDONLY)) < 0) {
// TODO error
return 0;
}
}
// Add tty to readfds
FD_ZERO(&readfds);
FD_SET(*ttyfd, &readfds);
// Add async procs to readfds
// Simultaneously check for solo, which takes precedence over everything
maxfd = *ttyfd;
DL_FOREACH(aprocs, aproc) {
FD_SET(aproc->rfd, &readfds);
if (aproc->rfd > maxfd) maxfd = aproc->rfd;
}
// Perform select
rc = select(maxfd + 1, &readfds, NULL, NULL, NULL);
if (rc < 0) {
return 0; // TODO error
} else if (rc == 0) {
return 1; // Nothing to read, call again
}
if (FD_ISSET(*ttyfd, &readfds)) {
// Immediately give priority to user input
return 0;
} else {
// Read async procs
DL_FOREACH_SAFE(aprocs, aproc, aproc_tmp) {
// Read and invoke callback
if (FD_ISSET(aproc->rfd, &readfds)) {
nbytes = read(aproc->rfd, &buf, 1024);
buf[nbytes] = '\0';
aproc->callback(aproc, buf, nbytes);
if (nbytes == 0) aproc->is_done = 1;
}
// Destroy on eof.
// Not sure if ferror and feof have any effect here given we're not
// using fread.
if (ferror(aproc->rpipe) || feof(aproc->rpipe) || aproc->is_done) {
aproc_destroy(aproc, 0);
}
}
}
return 1;
}