After encountering first unknown argument start treating the remaining arguments as command to be run.

This allows to not add quotes for the command that needs to be run.
This commit is contained in:
Konstantin Pereiaslov
2023-05-28 02:30:53 -05:00
parent 9b34d7392b
commit e3e90723b1
3 changed files with 51 additions and 6 deletions

View File

@@ -34,14 +34,14 @@ If you want to install it system-wide, run `sudo make install` or simply `sudo c
### Example 1:
runwhenidle -t 100 -v "cp /filea /fileb"
runwhenidle -t 100 -v cp /filea /fileb
Run the `cp` command and pause it while user is active. When user is inactive for 100 seconds, resume the command.
Output debug information to stderr.
### Example 2:
runwhenidle --timeout=300 -q "cat /dev/zero"
runwhenidle --timeout=300 -q cat /dev/zero
Run the `cat /dev/zero` command and pause it while user is active. `-q` option makes sure runwhenidle doesn't output anything other than the output of `cat /dev/zero`.

View File

@@ -1,6 +1,5 @@
Here are the planned changes:
* Add support of passing the command without quotes, like `watch`.
* Add support for --version|-V argument.
* AUR package.
* Look more into Wayland support.

52
main.c
View File

@@ -7,6 +7,8 @@
#include <sys/wait.h>
#include <X11/extensions/scrnsaver.h>
#include <getopt.h>
#include <string.h>
#include <assert.h>
#include "sleep_utils.h"
#include "time_utils.h"
@@ -83,6 +85,49 @@ void exit_if_pid_has_finished(pid_t pid) {
}
}
char *read_remaining_arguments_as_char(int argc,
char *const *argv) {
if (optind == argc) { //there is one argument remaining
char *last_and_only_argument = strdup(argv[optind]);
size_t last_argument_length = strlen(last_and_only_argument);
//check if it's quoted and if it is, get rid of the quotes
if (last_and_only_argument[0] == '"' && last_and_only_argument[last_argument_length - 1] == '"') {
// shift the argument string one position to the left, removing the leading quote
memmove(last_and_only_argument, last_and_only_argument + 1, last_argument_length - 2);
last_and_only_argument[last_argument_length - 2] = '\0'; // replace closing quote with null terminator
return last_and_only_argument;
}
return last_and_only_argument;
}
size_t memory_to_be_allocated_for_remaining_arguments_string = 0;
for (int i = optind; i < argc; i++) {
memory_to_be_allocated_for_remaining_arguments_string +=
strlen(argv[i]) + 1; // +1 for space separator or null terminator
}
char *remaining_arguments_string = NULL; // Variable to store the remaining_arguments_string
// Allocate memory for the remaining_arguments_string
remaining_arguments_string = malloc(memory_to_be_allocated_for_remaining_arguments_string);
if (remaining_arguments_string == NULL) {
fprintf(stderr, "Failed to allocate memory while parsing command to be ran.\n");
exit(1);
}
size_t current_length_of_all_arguments = 0;
for (int i = optind; i < argc; i++) {
size_t current_argument_length = strlen(argv[i]);
memcpy(remaining_arguments_string + current_length_of_all_arguments, argv[i], current_argument_length);
current_length_of_all_arguments += current_argument_length;
remaining_arguments_string[current_length_of_all_arguments++] = ' '; // Add space separator
}
assert(current_length_of_all_arguments == memory_to_be_allocated_for_remaining_arguments_string);
remaining_arguments_string[current_length_of_all_arguments - 1] = '\0'; // Replace the last space separator with a null terminator
return remaining_arguments_string;
}
int main(int argc, char *argv[]) {
pid_t pid;
long unsigned user_idle_timeout_ms = 300000;
@@ -93,12 +138,12 @@ int main(int argc, char *argv[]) {
{"verbose", no_argument, NULL, 'v'},
{"quiet", no_argument, NULL, 'q'},
{"help", no_argument, NULL, 'h'},
{NULL, 0, NULL, 0}
{NULL, 0, NULL, 0}
};
// Parse command line options
int option;
while ((option = getopt_long(argc, argv, "hvqt:", long_options, NULL)) != -1) {
while ((option = getopt_long(argc, argv, "+hvqt:", long_options, NULL)) != -1) {
switch (option) {
case 't':
const long TIMEOUT_MAX_SUPPORTED_VALUE = 100000000; //~3 years
@@ -132,6 +177,7 @@ int main(int argc, char *argv[]) {
print_usage(argv[0]);
return 1;
}
char *shell_command_to_run = read_remaining_arguments_as_char(argc, argv);
//Open display and initialize XScreensaverInfo for querying idle time
Display *dpy = XOpenDisplay(NULL);
@@ -141,7 +187,7 @@ int main(int argc, char *argv[]) {
}
XScreenSaverInfo *info = XScreenSaverAllocInfo();
pid = run_shell_command(argv[optind], pid);
pid = run_shell_command(shell_command_to_run, pid);
// Let command run for 300ms to give it a chance to error-out or provide initial output.
// 300ms is chosen to avoid giving user a noticeable delay while giving most quick commands a chance to finish.