summaryrefslogtreecommitdiff
path: root/http/pp
diff options
context:
space:
mode:
Diffstat (limited to 'http/pp')
-rw-r--r--http/pp/LICENSE15
-rw-r--r--http/pp/Makefile29
-rw-r--r--http/pp/README.md188
-rw-r--r--http/pp/pp.146
-rw-r--r--http/pp/pp.c369
-rw-r--r--http/pp/pp.obin0 -> 9168 bytes
6 files changed, 647 insertions, 0 deletions
diff --git a/http/pp/LICENSE b/http/pp/LICENSE
new file mode 100644
index 0000000..648cf93
--- /dev/null
+++ b/http/pp/LICENSE
@@ -0,0 +1,15 @@
+ISC License
+
+Copyright (c) 2021, Adrian Emil Grigore <adrian.emil.grigore@gmail.com>
+
+Permission to use, copy, modify, and/or distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
diff --git a/http/pp/Makefile b/http/pp/Makefile
new file mode 100644
index 0000000..afc122f
--- /dev/null
+++ b/http/pp/Makefile
@@ -0,0 +1,29 @@
+CC = cc
+LD = ${CC}
+
+PREFIX = /usr/local
+MANPREFIX = ${PREFIX}/share/man
+
+CFLAGS = -Wall -Wextra -pedantic
+
+pp: pp.o
+pp.o: pp.c
+
+.c.o:
+ $(CC) $(CPPFLAGS) $< $(CFLAGS) -c -o $@
+.o:
+ $(LD) $< $(LDFLAGS) -o $@
+
+clean:
+ rm -rf pp *.o
+
+install: pp pp.1
+ mkdir -p $(DESTDIR)$(PREFIX)/bin
+ mkdir -p $(DESTDIR)$(MANPREFIX)/man1
+ cp pp $(DESTDIR)$(PREFIX)/bin/pp
+ cp pp.1 $(DESTDIR)$(MANPREFIX)/man1/
+ chmod 755 $(DESTDIR)$(PREFIX)/bin/pp
+
+uninstall:
+ rm $(DESTDIR)$(PREFIX)/bin/pp
+ rm $(DESTDIR)$(MANPREFIX)/man1/pp.1
diff --git a/http/pp/README.md b/http/pp/README.md
new file mode 100644
index 0000000..f69faf1
--- /dev/null
+++ b/http/pp/README.md
@@ -0,0 +1,188 @@
+# `pp(1)`
+
+a preprocessor
+
+`pp(1)` allows embedding
+[`sh(1)`](https://pubs.opengroup.org/onlinepubs/9699919799/utilities/sh.html)
+code in files of any type by nesting it inside the `#!\n` token, where
+`\n` is a new line. That means that if you'd like a simple loop or an
+`if` inside an HTML file for instance,
+you could use `pp(1)`.
+
+## Basic usage
+
+For the following code:
+
+ <!doctype html>
+ <title>pp(1) example</title>
+ <ul>
+ #!
+ i=1
+ while test $i -le 10
+ do
+ if test $((i % 2)) -eq 0
+ then
+ #!
+ <li class=even>$i</li>
+ #!
+ else
+ #!
+ <li class=odd>$i</li>
+ #!
+ fi
+ i=$((i + 1))
+ done
+ #!
+ </ul>
+
+`pp(1)` outputs:
+
+ <!doctype html>
+ <title>pp(1) example</title>
+ <ul>
+ <li class=odd>1</li>
+ <li class=even>2</li>
+ <li class=odd>3</li>
+ <li class=even>4</li>
+ <li class=odd>5</li>
+ <li class=even>6</li>
+ <li class=odd>7</li>
+ <li class=even>8</li>
+ <li class=odd>9</li>
+ <li class=even>10</li>
+ </ul>
+
+## Arguments
+
+You can also pass arguments to it by appending them to the command call:
+
+ <!doctype html>
+ <title>$1</title>
+ <p>
+ #!
+ echo $2
+ #!
+ </p>
+
+Calling the above code with
+`pp tmp.upphtml 'pp(1) example' 'hello, world'`
+will result in:
+
+ <!doctype html>
+ <title>pp(1) example</title>
+ <p>
+ hello world
+ </p>
+
+## Pipes
+
+`pp(1)`'s `stdin` is sent to the child
+[`sh(1)`](https://pubs.opengroup.org/onlinepubs/9699919799/utilities/sh.html)
+
+ <!doctype html>
+ <title>pp(1) example</title>
+ <p>
+ #!
+ cat
+ #!
+ </p>
+
+`echo 'hello, world' | pp tmp.upphtml` will output:
+
+ <!doctype html>
+ <title>pp(1) example</title>
+ <p>
+ hello, world
+ </p>
+
+## Debugging
+
+`pp(1)` also takes an optional `-d` flag. If passed, `pp(1)` will dump
+the generated
+[`sh(1)`](https://pubs.opengroup.org/onlinepubs/9699919799/utilities/sh.html)
+code instead of executing it:
+
+ <!doctype html>
+ <title>pp(1) example</title>
+ <ul>
+ #!
+ i=1
+ while test $i -le 10
+ do
+ if test $((i % 2)) -eq 0
+ then
+ #!
+ <li class=even>$i</li>
+ #!
+ else
+ #!
+ <li class=odd>$i</li>
+ #!
+ fi
+ i=$((i + 1))
+ done
+ #!
+ </ul>
+
+`pp -d tmp.upphtml` will output:
+
+ echo "<!doctype html>
+ <title>pp(1) example</title>
+ <ul>"
+ i=1
+ while test $i -le 10
+ do
+ if test $((i % 2)) -eq 0
+ then
+ echo " <li class=even>$i</li>"
+ else
+ echo " <li class=odd>$i</li>"
+ fi
+ i=$((i + 1))
+ done
+ echo "</ul>"
+
+## Example
+
+ <!doctype html>
+ <html lang=en>
+ <title>pp(1)</title>
+ <meta charset=UTF-8>
+ <meta name=viewport content='width=device-width'>
+ <link rel=stylesheet href=../theme.css>
+ <body>
+ <a href=../#myprojects>Home</a>
+ #!
+ addcls() {
+ sed "s/<code>/<code class=language-bash>/g"
+ }
+ smu README | addcls
+ #!
+ <h2>Files</h2>
+ <ul>
+ #!
+ for f in *
+ do
+ case $f in
+ *.upp*|*.html|*.tgz)
+ continue
+ ;;
+ esac
+ #!
+ <li><a href=$f>$f</a></li>
+ #!
+ done
+ #!
+ </ul>
+ <h2>Download</h2>
+ <a href=pp.tgz>pp.tgz</a>
+ <script src=../prism.js data-manual></script>
+ <script src=../enhance.js></script>
+ </body>
+ </html>
+
+## See also
+
+* <https://github.com/radare/spp>
+* <https://werc.cat-v.org/docs/rc-template-lang>
+* <https://code.9front.org/hg/werc/file/92f7463dac1a/bin/template.awk>
diff --git a/http/pp/pp.1 b/http/pp/pp.1
new file mode 100644
index 0000000..a552c97
--- /dev/null
+++ b/http/pp/pp.1
@@ -0,0 +1,46 @@
+.Dd Apr 25, 2019
+.Dt pp 1
+.Os
+.Sh NAME
+.Nm pp
+.Nd preprocessor
+.Sh SYNOPSIS
+.Nm pp
+.Op Fl d
+.Ar file
+.Op args ...
+.Sh DESCRIPTION
+The
+.Nm
+utility processes
+.Ar file
+to produce output that is used as input to another
+program.
+.Pp
+It executes code enclosed in
+.Dq #!\en
+delimiters using
+.Xr sh 1 .
+.Op args ...
+are passed to the embbeded script and are available
+via the usual
+.Em $1, $2, ...
+positional parameters.
+.Pp
+The options are as follows:
+.Bl -tag -width Ds
+.It Fl d
+.Nm
+will dump the generated
+.Xr sh 1
+code instead of executing it. This is useful for debugging.
+.El
+.Sh EXIT STATUS
+.Ex -std
+.Sh EXAMPLES
+Preprocess file with arguments:
+.Pp
+.Dl $ pp file.upphtml a b
+.Pp
+.Sh SEE ALSO
+.Xr sh 1
diff --git a/http/pp/pp.c b/http/pp/pp.c
new file mode 100644
index 0000000..340f430
--- /dev/null
+++ b/http/pp/pp.c
@@ -0,0 +1,369 @@
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#if !__APPLE__
+/*
+ * Appends src to string dst of size dsize (unlike strncat, dsize is the
+ * full size of dst, not space left). At most dsize-1 characters
+ * will be copied. Always NUL terminates (unless dsize <= strlen(dst)).
+ * Returns strlen(src) + MIN(dsize, strlen(initial dst)).
+ * If retval >= dsize, truncation occurred.
+ */
+size_t
+strlcat(char *dst, const char *src, size_t dsize)
+{
+ const char *odst = dst;
+ const char *osrc = src;
+ size_t n = dsize;
+ size_t dlen;
+
+ /* Find the end of dst and adjust bytes left but don't go past end. */
+ while (n-- != 0 && *dst != '\0')
+ dst++;
+ dlen = dst - odst;
+ n = dsize - dlen;
+
+ if (n-- == 0)
+ return(dlen + strlen(src));
+ while (*src != '\0') {
+ if (n != 0) {
+ *dst++ = *src;
+ n--;
+ }
+ src++;
+ }
+ *dst = '\0';
+
+ return(dlen + (src - osrc)); /* count does not include NUL */
+}
+#endif /* !__APPLE__ */
+
+#define MAXSIZE 12000
+#define MAXINDENTSIZE 80
+#define MAXARGSIZE 20
+
+char *argv0;
+
+int
+efgetc(FILE *fp)
+{
+ int c;
+
+ c = fgetc(fp);
+
+ if (c == EOF &&
+ ferror(fp) != 0) {
+ perror(argv0);
+ exit(1);
+ }
+
+ return c;
+}
+
+int
+efseek(FILE *fp, long offset, int whence)
+{
+ int s;
+
+ s = fseek(fp, offset, whence);
+
+ if (s == -1) {
+ perror(argv0);
+ exit(1);
+ }
+
+ return s;
+}
+
+int
+eungetc(int c, FILE *fp)
+{
+ int uc;
+
+ uc = ungetc(c, fp);
+
+ if (uc == EOF) {
+ perror(argv0);
+ exit(1);
+ }
+
+ return uc;
+}
+
+size_t
+estrlcat(char *dst, const char *src, size_t dstsize)
+{
+ size_t n;
+
+ n = strlcat(dst, src, dstsize);
+
+ if (n >= dstsize) {
+ fprintf(stderr, "%s: Buffer overflow\n", argv0);
+ exit(1);
+ }
+
+ return n;
+}
+
+int
+eclose(int d)
+{
+ int s;
+
+ s = close(d);
+
+ if (s == -1) {
+ perror(argv0);
+ exit(1);
+ }
+
+ return s;
+}
+
+char *
+strappend(char *s, char c)
+{
+ size_t len;
+
+ len = strlen(s);
+
+ s[len] = c;
+ s[len + 1] = '\0';
+
+ return s ;
+}
+
+int
+shebang(FILE *fp)
+{
+ int c;
+
+ c = efgetc(fp);
+
+ if (c != '#') {
+ eungetc(c, fp);
+ return 0;
+ }
+
+ c = efgetc(fp);
+
+ if (c != '!') {
+ eungetc(c, fp);
+ eungetc('#', fp);
+ return 0;
+ }
+
+ c = efgetc(fp);
+
+ if (c == '\n') {
+ eungetc(c, fp);
+ eungetc('!', fp);
+ eungetc('#', fp);
+ return 0;
+ }
+
+ for (;;) {
+ c = efgetc(fp);
+ if (c == '\n')
+ break;
+ }
+
+ return 1;
+}
+
+int
+token(FILE *fp, int consume)
+{
+ int c;
+
+ c = efgetc(fp);
+
+ if (c != '#') {
+ eungetc(c, fp);
+ return 0;
+ }
+
+ c = efgetc(fp);
+ if (c != '!') {
+ eungetc(c, fp);
+ eungetc('#', fp);
+ return 0;
+ };
+
+ c = efgetc(fp);
+
+ if (c != '\n') {
+ eungetc(c, fp);
+ eungetc('!', fp);
+ eungetc('#', fp);
+ return 0;
+ }
+
+ if (consume == 0) {
+ eungetc(c, fp);
+ eungetc('!', fp);
+ eungetc('#', fp);
+ }
+
+ return 1;
+}
+
+size_t
+output(char *s)
+{
+ return estrlcat(s, "echo \"", MAXSIZE);
+}
+
+size_t
+outputend(char *s)
+{
+ return estrlcat(s, "\"\n", MAXSIZE);
+}
+
+int main(int argc, char **argv)
+{
+ char s[MAXSIZE] = "", indent[MAXINDENTSIZE] = "",
+ *eargv[MAXARGSIZE] = {"sh", "-c", s, "sh", NULL};
+ FILE *fp;
+ int size, c, i, fd[2], o = 0, status = 0, d = 0;
+
+
+ argv0 = argv[0];
+ if (argc == 1) {
+ fprintf(stderr, "usage: %s file [args ...]\n", argv[0]);
+ return 1;
+
+ }
+
+ if (strcmp(argv[1], "-d") == 0) {
+ if (argc == 2) {
+ fprintf(stderr, "usage: %s file [args ...]\n", argv[0]);
+ return 1;
+
+ }
+ d = 1;
+ fp = fopen(argv[2], "r");
+ } else {
+ fp = fopen(argv[1], "r");
+ }
+
+
+ if (!fp) {
+ fprintf(stderr, "%s: %s: %s\n",
+ argv[0], d ? argv[2] : argv[1], strerror(errno));
+ return 1;
+ }
+
+ efseek (fp, 0, SEEK_END);
+ size = ftell(fp);
+
+ if(size == 0) return 0;
+
+ efseek(fp, -1, SEEK_END);
+ c = efgetc(fp);
+
+ if (c != '\n') {
+ fprintf(stderr, "%s: %s: No newline at end of file\n",
+ argv[0], d ? argv[2] : argv[1]);
+ exit(1);
+ }
+
+ efseek(fp, 0, SEEK_SET);
+
+ shebang(fp);
+
+ if (!token(fp, 1)) {
+ output(s);
+ o = 1;
+ }
+
+ for(;;) {
+ if (token(fp, 1)) {
+ if (!o) {
+ c = efgetc(fp);
+ if (c == EOF)
+ goto done;
+ eungetc(c, fp);
+ output(s);
+ } else
+ outputend(s);
+ o = !o;
+ }
+
+ c = efgetc(fp);
+ if (c == EOF)
+ break;
+
+ if (c == '\n') {
+ indent[0] = 0;
+ c = efgetc(fp);
+ if (c == EOF)
+ break;
+
+ for (;;) {
+ if (c != ' ' && c != '\t')
+ break;
+ strappend(indent, c);
+ c = efgetc(fp);
+ if (c == EOF)
+ break;
+ }
+
+ eungetc(c, fp);
+
+ if (token(fp, 0) && o)
+ continue;
+
+ strappend(s, '\n');
+ estrlcat(s, indent, MAXSIZE);
+ continue;
+ }
+
+ strappend(s, c);
+ }
+ if (o) {
+ outputend(s);
+ o = 0;
+ }
+ done:
+
+ if(d) {
+ puts(s);
+ return 0;
+ }
+
+ if (pipe(fd) == -1) {
+ perror(argv0);
+ return 1;
+ }
+
+ switch (fork()) {
+ case -1:
+ perror(argv0);
+ return 1;
+ case 0:
+ eclose(fd[1]);
+ eclose(fd[0]);
+ for (i = 2; i < argc; i++)
+ eargv[i+2] = argv[i];
+
+ if (execv("/bin/sh", eargv) == -1) {
+ perror(argv0);
+ return 1;
+ }
+ break;
+ default:
+ eclose(fd[1]);
+ eclose(fd[0]);
+ if (wait(&status) == -1) {
+ perror(argv0);
+ return 1;
+ }
+ }
+
+ return status;
+}
diff --git a/http/pp/pp.o b/http/pp/pp.o
new file mode 100644
index 0000000..7c3f385
--- /dev/null
+++ b/http/pp/pp.o
Binary files differ