forked from jordansissel/xdotool
-
Notifications
You must be signed in to change notification settings - Fork 0
/
cmd_exec.c
130 lines (115 loc) · 3.56 KB
/
cmd_exec.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
#include "xdo_cmd.h"
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
int cmd_exec(context_t *context) {
char *cmd = *context->argv;
char **command = NULL;
int command_count = 0;
int ret = EXIT_SUCCESS;
int opsync = 0;
int arity = -1;
char *terminator = NULL;
int c, i;
typedef enum {
opt_unused, opt_help, opt_sync, opt_args, opt_terminator
} optlist_t;
static struct option longopts[] = {
{ "help", no_argument, NULL, opt_help },
{ "sync", no_argument, NULL, opt_sync },
{ "args", required_argument, NULL, opt_args },
{ "terminator", required_argument, NULL, opt_terminator },
{ 0, 0, 0, 0 },
};
static const char *usage =
"Usage: %s [options] command [arg1 arg2 ...] [terminator]\n"
"--sync - only exit when the command given finishes. The default\n"
" is to fork a child process and continue.\n"
"--args N - how many arguments to expect in the exec command. This is\n"
" useful for ending an exec and continuing with more xdotool\n"
" commands\n"
"--terminator TERM - similar to --args, specifies a terminator that\n"
" marks the end of 'exec' arguments. This is useful\n"
" for continuing with more xdotool commands.\n"
"\n"
"Unless --args OR --terminator is specified, the exec command is assumed\n"
"to be the remainder of the command line.\n";
int option_index;
while ((c = getopt_long_only(context->argc, context->argv, "+h",
longopts, &option_index)) != -1) {
switch (c) {
case 'h':
case opt_help:
printf(usage, cmd);
consume_args(context, context->argc);
return EXIT_SUCCESS;
break;
case opt_sync:
opsync = 1;
break;
case opt_args:
arity = atoi(optarg);
break;
case opt_terminator:
terminator = strdup(optarg);
break;
default:
fprintf(stderr, usage, cmd);
return EXIT_FAILURE;
}
}
consume_args(context, optind);
if (context->argc == 0) {
fprintf(stderr, "No arguments given.\n");
fprintf(stderr, usage, cmd);
return EXIT_FAILURE;
}
if (arity > 0 && terminator != NULL) {
fprintf(stderr, "Don't use both --terminator and --args.\n");
return EXIT_FAILURE;
}
if (context->argc < arity) {
fprintf(stderr, "You said '--args %d' but only gave %d arguments.\n",
arity, context->argc);
return EXIT_FAILURE;
}
command = calloc(context->argc + 1, sizeof(char *));
for (i=0; i < context->argc; i++) {
if (arity > 0 && i == arity) {
break;
}
/* if we have a terminator and the current argument matches it... */
if (terminator != NULL && strcmp(terminator, context->argv[i]) == 0) {
command_count++; /* Consume the terminator, too */
break;
}
command[i] = strdup(context->argv[i]);
command_count = i + 1; /* i starts at 0 */
xdotool_debug(context, "Exec arg[%d]: %s", i, command[i]);
}
command[i] = NULL;
pid_t child;
child = fork();
if (child == 0) { /* child */
execvp(command[0], command);
/* if we get here, there was an error */
perror("execvp failed");
exit(errno);
} else { /* parent */
if (opsync) {
int status = 0;
waitpid(child, &status, 0);
ret = WEXITSTATUS(status);
}
}
consume_args(context, command_count);
if (terminator != NULL) {
free(terminator);
}
for (i=0; i < command_count; i++) {
free(command[i]);
}
free(command);
return ret;
}