summaryrefslogtreecommitdiff
path: root/http/pp/pp.c
diff options
context:
space:
mode:
authorJoe Carstairs <me@joeac.net>2026-06-17 21:46:49 +0100
committerJoe Carstairs <me@joeac.net>2026-06-17 21:48:24 +0100
commit6dd4caf947f2997698ebf7354172a6476ad0bf25 (patch)
treebcdd557656119dc028234d67396930c124ee0735 /http/pp/pp.c
parent506d1adfccbb494be598e08f8d45aaae641eb6d2 (diff)
adds pp sources
Diffstat (limited to 'http/pp/pp.c')
-rw-r--r--http/pp/pp.c369
1 files changed, 369 insertions, 0 deletions
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;
+}