Finalize project

This commit is contained in:
Nero 2022-09-11 14:51:37 +00:00
commit c75cbff329
4 changed files with 95 additions and 0 deletions

10
Makefile Normal file
View File

@ -0,0 +1,10 @@
PROGS = sh_quote
CFLAGS = -std=c99 -pedantic
default: $(PROGS)
test: $(PROGS)
./test_sh_quote
clean:
rm -f $(PROGS)

39
README.md Normal file
View File

@ -0,0 +1,39 @@
# Shell quoting util
This tool was made to handle a specific edge case in shell scripting.
When you want to supply a command to some tool as a shell string, but you only have it as already expanded array.
This doesn't work as expected because `$@` is expanded, ending up as multiple arguments to `su`:
```
su -c "$@"
```
This does work as expected:
```
su -c "$(sh_quote "$@")"
```
Because all arguments must be relayed, `-h` or `--help` cannot be taken into account, so there is no helptext.
When no arguments are given, it returns without producing any output.
# Error messages
None. This program cannot fail.
If stdout is not writable, no sensible output will be generated.
If `$0` is not set, no output will be generated.
# Building
Run `make`.
# Testing
Run `make test`
The test script can also run on arbitrary programs: `./run_sh_quote /path/to/other_program`.

26
sh_quote.c Normal file
View File

@ -0,0 +1,26 @@
#include <stdio.h>
#include <string.h>
int main(int argc, char** argv) {
unsigned int i;
char* p;
char* delim = "'";
for (i = 1; i < argc; i++) {
if (i > 1) putchar(' ');
p = argv[i];
printf("%s", delim);
while(*p != '\0') {
if (p[0] == '\'') {
printf("%s\\'%s", delim, delim);
p++;
continue;
}
if (p[0] == '\\') putchar('\\');
putchar((p++)[0]);
}
printf("%s", delim);
}
putchar('\n');
return 0;
}

20
test_sh_quote Executable file
View File

@ -0,0 +1,20 @@
#!/bin/sh
PROG=${1:-./sh_quote}
run_test() {
r=$($PROG "$2"|sed 's/^ *//;s/ *$//')
if test "$r" == "$3"; then
echo PASS "$1"
else
echo FAIL "$1"
printf "Expected: %s\nGot: %s\n" "$3" "$r"
fi
}
run_test empty "" "''"
run_test whitespace "Foo Bar" "'Foo Bar'"
run_test quote "Foo'Bar" "'Foo'\''Bar'"
run_test newline "Foo
Bar" "'Foo
Bar'"
run_test trailing_space "Foobar " "'Foobar '"