diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..e4e28ad --- /dev/null +++ b/LICENSE @@ -0,0 +1,24 @@ +Copyright (c) 2018, Michel Martens + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..f0b940a --- /dev/null +++ b/README.md @@ -0,0 +1,53 @@ +# map + +Map lines from stdin to commands. + +Description +----------- + +Map lets you process each line from stdin with a command of your +choice. For example: + +```shell +$ ls +LICENSE README.md makefile map.1 map.c +``` + +```shell +$ ls | map f 'echo $f $f' +LICENSE LICENSE +README.md README.md +makefile makefile +map.1 map.1 +map.c map.c +``` + +Note that the command must be wrapped in single quotes to prevent +the variable from being expanded by the shell. + +Installation +------------ + +Install map into `/usr/local/bin` with the following command: + + $ make install + +You can use `make PREFIX=/some/other/directory install` if you wish +to use a different destination. If you want to remove map from +your system, use `make uninstall`. + +Motivation +---------- + +There are many ways to accomplish what you can do with `map`, +including shell builtins, `find`, `awk`, etc. The approach taken +by `map` is extremely pragmatic and allows me to express concisely +what I want. Given the fact that it's designed as a filter, it can +operate on any kind of list, not only lists of files. + +Contributing +------------ + +If you find a bug, please create an issue detailing the ways to +reproduce it. If you have a suggestion, create an issue detailing +the use case. diff --git a/makefile b/makefile new file mode 100644 index 0000000..96f4124 --- /dev/null +++ b/makefile @@ -0,0 +1,36 @@ +PREFIX?=/usr/local +MANPREFIX?=${PREFIX}/share/man +STRIP?=strip + +default: map + +map: map.c + $(CC) -Wall -Os -o map map.c + +clean: + @echo cleaning + @rm -f map + +install: map + @echo stripping executable + @${STRIP} map + @echo installing executable to ${PREFIX}/bin + @mkdir -p ${PREFIX}/bin + @cp -f map ${PREFIX}/bin/map + @chmod 755 ${PREFIX}/bin/map + + @echo installing manual pages to ${MANPREFIX}/man1 + @mkdir -p ${MANPREFIX}/man1 + @cp -f map.1 ${MANPREFIX}/man1/map.1 + @chmod 644 ${MANPREFIX}/man1/map.1 + +uninstall: + @echo removing executable from ${PREFIX}/bin + @rm ${PREFIX}/bin/map + @echo removing manual pages from ${MANPREFIX}/man1 + @rm ${MANPREFIX}/man1/map.1 + +test: + @sh test/tests.sh + +.PHONY: clean install uninstall test diff --git a/map.1 b/map.1 new file mode 100644 index 0000000..2ce181c --- /dev/null +++ b/map.1 @@ -0,0 +1,39 @@ +.Dd March 11, 2018 +.Dt MAP 1 +. +.Sh NAME +. +.Nm map +.Nd Map lines from stdin to commands. +. +.Sh SYNOPSIS +. +.Nm +.Ar variable +.Ar command +. +.Sh DESCRIPTION +. +.Nm +lets you process each line from stdin with a command of your +choice. +. +.Sh EXAMPLES +. +Here's an example: +.Pp +.Dl $ ls +.Dl Sy LICENSE README.md makefile map.1 map.c +.Pp +.Dl $ ls | map f 'echo $f $f' +.Dl Sy LICENSE LICENSE +.Dl Sy README.md README.md +.Dl Sy makefile makefile +.Dl Sy map.1 map.1 +.Dl Sy map.c map.c +.Pp +Note that the command must be wrapped in single quotes to prevent +the variable from being expanded by the shell. +. +.Sh AUTHOR +.An Michel Martens Aq mail@soveran.com diff --git a/map.c b/map.c new file mode 100644 index 0000000..2c1ea63 --- /dev/null +++ b/map.c @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2018, Michel Martens + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include + +int main(int argc, char **argv) { + + if (argc != 3) { + printf("usage: %s \n", argv[0]); + exit(1); + } + + char *line = NULL; + size_t lcap = 0; + ssize_t llen; + + while ((llen = getline(&line, &lcap, stdin)) > 0) { + setenv(argv[1], line, 1); + system(argv[2]); + } + + return 0; +} diff --git a/test/input b/test/input new file mode 100644 index 0000000..86e041d --- /dev/null +++ b/test/input @@ -0,0 +1,3 @@ +foo +bar +baz diff --git a/test/tests.sh b/test/tests.sh new file mode 100755 index 0000000..b611c58 --- /dev/null +++ b/test/tests.sh @@ -0,0 +1,8 @@ +#!/bin/sh + +assert_equal () { + test "$1" = "$2" || printf "F: \"%s\" != \"%s\"\n" $1 $2 +} + +assert_equal "foofoo" `printf foo | ./map f 'printf $f$f'` +assert_equal "foobarbaz" `cat ./test/input | ./map f 'printf $f'`