From 6dd4caf947f2997698ebf7354172a6476ad0bf25 Mon Sep 17 00:00:00 2001 From: Joe Carstairs Date: Wed, 17 Jun 2026 21:46:49 +0100 Subject: [PATCH] adds pp sources --- http/pp/LICENSE | 15 ++ http/pp/Makefile | 29 ++++ http/pp/README.md | 188 +++++++++++++++++++++++ http/pp/pp.1 | 46 ++++++ http/pp/pp.c | 369 ++++++++++++++++++++++++++++++++++++++++++++++ http/pp/pp.o | Bin 0 -> 9168 bytes 6 files changed, 647 insertions(+) create mode 100644 http/pp/LICENSE create mode 100644 http/pp/Makefile create mode 100644 http/pp/README.md create mode 100644 http/pp/pp.1 create mode 100644 http/pp/pp.c create mode 100644 http/pp/pp.o 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 + +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: + + + pp(1) example + + +`pp(1)` outputs: + + + pp(1) example + + +## Arguments + +You can also pass arguments to it by appending them to the command call: + + + $1 +

+ #! + echo $2 + #! +

+ +Calling the above code with +`pp tmp.upphtml 'pp(1) example' 'hello, world'` +will result in: + + + pp(1) example +

+ hello world +

+ +## Pipes + +`pp(1)`'s `stdin` is sent to the child +[`sh(1)`](https://pubs.opengroup.org/onlinepubs/9699919799/utilities/sh.html) + + + pp(1) example +

+ #! + cat + #! +

+ +`echo 'hello, world' | pp tmp.upphtml` will output: + + + pp(1) example +

+ hello, world +

+ +## 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: + + + pp(1) example + + +`pp -d tmp.upphtml` will output: + + echo " + pp(1) example + " + +## Example + + + + pp(1) + + + + + Home + #! + addcls() { + sed "s///g" + } + smu README | addcls + #! +

Files

+
    + #! + for f in * + do + case $f in + *.upp*|*.html|*.tgz) + continue + ;; + esac + #! +
  • $f
  • + #! + done + #! +
+

Download

+ pp.tgz + + + + + +## See also + +* +* +* 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 +#include +#include +#include +#include +#include + +#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 0000000000000000000000000000000000000000..7c3f385d2227b744c29eec7a48c584478b68450c GIT binary patch literal 9168 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 P2w%!TbgQwi?(zQta1^Tz literal 0 HcmV?d00001