From b975b7392606050c1ed83a8cce016f872589ad38 Mon Sep 17 00:00:00 2001 From: Tristan Riehs Date: Thu, 28 Sep 2023 08:08:38 +0200 Subject: source moved --- Makefile | 8 ++-- rpt.1 | 36 +++++++++++++++ rpt.c | 150 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/rpt.c | 150 -------------------------------------------------------------- 4 files changed, 190 insertions(+), 154 deletions(-) create mode 100644 rpt.1 create mode 100644 rpt.c delete mode 100644 src/rpt.c diff --git a/Makefile b/Makefile index 405f968..fa63f68 100644 --- a/Makefile +++ b/Makefile @@ -3,11 +3,11 @@ PREFIX = /usr/local CFLAGS = -std=c99 -Wall -Wextra -pedantic -O0 -ggdb BIN = rpt -SRC = src/rpt.c -OBJ = src/rpt.o +SRC = rpt.c +OBJ = rpt.o -MAN_SRC = man/rpt.1 -MAN_PAGE = man/rpt.1.gz +MAN_SRC = rpt.1 +MAN_PAGE = rpt.1.gz .PHONY: all compile man clean install uninstall diff --git a/rpt.1 b/rpt.1 new file mode 100644 index 0000000..49920a6 --- /dev/null +++ b/rpt.1 @@ -0,0 +1,36 @@ +.\" Written by Tristan Riehs. +.\" This file is part of repeat and is licensed under the MIT License. +.TH rpt 1 2023-09-27 + +.SH NAME +rpt \- repeat a shell command + +.SH SYNOPSIS +.B rpt + +.SH DESCRIPTION + +.SH OPTIONS + +.SH "EXIT STATUS" +.1 Invalid option. + +.2 Error while reading +.IR COUNT . + +.3 +.I COMMAND +not provided. + +.SH FILES +None. + +.SH "SEE ALSO" +.BR seq (1) + +.SH BUGS +Please report bugs at +.IR https://gitlab.com/tristanriehs/repeat . + +.SH AUTHOR +Tristan Riehs diff --git a/rpt.c b/rpt.c new file mode 100644 index 0000000..1a9a256 --- /dev/null +++ b/rpt.c @@ -0,0 +1,150 @@ +#define _GNU_SOURCE /* getopt_long */ + +#include +#include +#include +#include +#include + +#define VERSION "1.0.0" + +void +print_usage(FILE *output) +{ + fprintf(output, "Usage:\n"); + fprintf(output, "rpt [-n | --count COUNT] [-f | --force] COMMAND\n"); + fprintf(output, "rpt [-h | --help]\n"); + fprintf(output, "rpt [-V | --version]\n"); +} + +void +print_help() +{ + puts("Repeat : repeat a shell command"); + puts(""); + print_usage(stdout); +} + +void +print_version() +{ + puts(VERSION); +} + +/* Exit whenever a subprocess fails. */ +void +exit_on_error(int status) +{ + if (WIFEXITED(status)) + return; + + fprintf(stderr, "Process exited with status %d, aborting.\n", status); + exit(1); +} + +/* Ignore subprocesses' errors. */ +void +continue_on_error(int status) +{ + (void) status; +} + +/* Invoke the executable *ARGV COUNT times, passing it the rest of ARG as + arguments. Call HANDLE_ERROR_F between each process. */ +void +repeat_cmd(char **argv, long count, void (*handle_error_f)(int)) +{ + pid_t pid; + int status; + + for(long i = 0; i < count; ++i) + { + pid = fork(); + + if (pid == 0) + { + /* child */ + status = execvp(argv[0], argv); + + if (status < 0) + exit(1); + + exit(2); + } + else + { + /* parent */ + int exit_status = 0; + + waitpid(pid, &exit_status, 0); + + handle_error_f(exit_status); + } + } +} + +int +main(int argc, char* argv[]) +{ + struct option const opts[] = { + {"count", required_argument, NULL, 'n'}, + {"force", no_argument, NULL, 'f'}, + {"version", no_argument, NULL, 'V'}, + {"help", no_argument, NULL, 'h'}, + {NULL, 0, NULL, 0} + }; + + opterr = 0; /* dismiss getopt error message */ + int opt; + + char *strcount = NULL; + long count = 1; + + void (*handle_error_f)(int status) = exit_on_error; + + while ((opt = getopt_long(argc, argv, "+:n:fVh", opts, NULL)) >= 0) + { + switch(opt) + { + case 'n': + strcount = optarg; + break; + case 'f': + handle_error_f = continue_on_error; + break; + case 'h': + print_help(); + return 0; + case 'V': + print_version(); + return 0; + case ':': + fprintf(stderr, "COUNT value missing.\n"); + print_usage(stderr); + return 1; /* invalid option */ + default: + print_usage(stderr); + return 1; /* invalid option */ + } + } + + if (strcount) + { + char *err = NULL; + count = strtol(strcount, &err, 10); + + if (err && (*err != '\0')) + { + fprintf(stderr, "Failed to read COUNT : '%s'.\n", + strcount); + return 2; /* error while reading COUNT */ + } + } + + if (optind >= argc) + return 3; /* COMMAND not provided */ + + repeat_cmd(argv + optind, count, handle_error_f); + + return 0; +} diff --git a/src/rpt.c b/src/rpt.c deleted file mode 100644 index 1a9a256..0000000 --- a/src/rpt.c +++ /dev/null @@ -1,150 +0,0 @@ -#define _GNU_SOURCE /* getopt_long */ - -#include -#include -#include -#include -#include - -#define VERSION "1.0.0" - -void -print_usage(FILE *output) -{ - fprintf(output, "Usage:\n"); - fprintf(output, "rpt [-n | --count COUNT] [-f | --force] COMMAND\n"); - fprintf(output, "rpt [-h | --help]\n"); - fprintf(output, "rpt [-V | --version]\n"); -} - -void -print_help() -{ - puts("Repeat : repeat a shell command"); - puts(""); - print_usage(stdout); -} - -void -print_version() -{ - puts(VERSION); -} - -/* Exit whenever a subprocess fails. */ -void -exit_on_error(int status) -{ - if (WIFEXITED(status)) - return; - - fprintf(stderr, "Process exited with status %d, aborting.\n", status); - exit(1); -} - -/* Ignore subprocesses' errors. */ -void -continue_on_error(int status) -{ - (void) status; -} - -/* Invoke the executable *ARGV COUNT times, passing it the rest of ARG as - arguments. Call HANDLE_ERROR_F between each process. */ -void -repeat_cmd(char **argv, long count, void (*handle_error_f)(int)) -{ - pid_t pid; - int status; - - for(long i = 0; i < count; ++i) - { - pid = fork(); - - if (pid == 0) - { - /* child */ - status = execvp(argv[0], argv); - - if (status < 0) - exit(1); - - exit(2); - } - else - { - /* parent */ - int exit_status = 0; - - waitpid(pid, &exit_status, 0); - - handle_error_f(exit_status); - } - } -} - -int -main(int argc, char* argv[]) -{ - struct option const opts[] = { - {"count", required_argument, NULL, 'n'}, - {"force", no_argument, NULL, 'f'}, - {"version", no_argument, NULL, 'V'}, - {"help", no_argument, NULL, 'h'}, - {NULL, 0, NULL, 0} - }; - - opterr = 0; /* dismiss getopt error message */ - int opt; - - char *strcount = NULL; - long count = 1; - - void (*handle_error_f)(int status) = exit_on_error; - - while ((opt = getopt_long(argc, argv, "+:n:fVh", opts, NULL)) >= 0) - { - switch(opt) - { - case 'n': - strcount = optarg; - break; - case 'f': - handle_error_f = continue_on_error; - break; - case 'h': - print_help(); - return 0; - case 'V': - print_version(); - return 0; - case ':': - fprintf(stderr, "COUNT value missing.\n"); - print_usage(stderr); - return 1; /* invalid option */ - default: - print_usage(stderr); - return 1; /* invalid option */ - } - } - - if (strcount) - { - char *err = NULL; - count = strtol(strcount, &err, 10); - - if (err && (*err != '\0')) - { - fprintf(stderr, "Failed to read COUNT : '%s'.\n", - strcount); - return 2; /* error while reading COUNT */ - } - } - - if (optind >= argc) - return 3; /* COMMAND not provided */ - - repeat_cmd(argv + optind, count, handle_error_f); - - return 0; -} -- cgit v1.2.3