summary refs log tree commit diff
path: root/pkgs/build-support/expand-response-params
diff options
context:
space:
mode:
authorJohn Ericson <John.Ericson@Obsidian.Systems>2017-08-23 16:23:30 -0400
committerJohn Ericson <John.Ericson@Obsidian.Systems>2017-08-25 11:21:09 -0400
commit287fce6402100c40317233de6b4f749f2b79b0a5 (patch)
tree845fac8eeaba363f5ddd3dcc720a5dd7b61f36de /pkgs/build-support/expand-response-params
parent2e7a3902122a269d751e31823c1c6c6b3ffa5c9b (diff)
downloadnixpkgs-287fce6402100c40317233de6b4f749f2b79b0a5.tar
nixpkgs-287fce6402100c40317233de6b4f749f2b79b0a5.tar.gz
nixpkgs-287fce6402100c40317233de6b4f749f2b79b0a5.tar.bz2
nixpkgs-287fce6402100c40317233de6b4f749f2b79b0a5.tar.lz
nixpkgs-287fce6402100c40317233de6b4f749f2b79b0a5.tar.xz
nixpkgs-287fce6402100c40317233de6b4f749f2b79b0a5.tar.zst
nixpkgs-287fce6402100c40317233de6b4f749f2b79b0a5.zip
expand-response-params: Pull out of cc-wrapper
No hashes were changed
Diffstat (limited to 'pkgs/build-support/expand-response-params')
-rw-r--r--pkgs/build-support/expand-response-params/default.nix13
-rw-r--r--pkgs/build-support/expand-response-params/expand-response-params.c84
2 files changed, 97 insertions, 0 deletions
diff --git a/pkgs/build-support/expand-response-params/default.nix b/pkgs/build-support/expand-response-params/default.nix
new file mode 100644
index 00000000000..7afbb727fc3
--- /dev/null
+++ b/pkgs/build-support/expand-response-params/default.nix
@@ -0,0 +1,13 @@
+{ stdenv }:
+
+stdenv.mkDerivation {
+  name = "expand-response-params";
+  src = ./expand-response-params.c;
+  buildCommand = ''
+    # Work around "stdenv-darwin-boot-2 is not allowed to refer to path /nix/store/...-expand-response-params.c"
+    cp "$src" expand-response-params.c
+    "$CC" -std=c99 -O3 -o "$out" expand-response-params.c
+    strip -S $out
+    ${stdenv.lib.optionalString stdenv.hostPlatform.isLinux "patchelf --shrink-rpath $out"}
+  '';
+}
diff --git a/pkgs/build-support/expand-response-params/expand-response-params.c b/pkgs/build-support/expand-response-params/expand-response-params.c
new file mode 100644
index 00000000000..05b9c62b1e8
--- /dev/null
+++ b/pkgs/build-support/expand-response-params/expand-response-params.c
@@ -0,0 +1,84 @@
+#include <assert.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+typedef struct { char *data; size_t len, cap; } String;
+
+void resize(String *s, size_t len) {
+    s->len = len;
+    if (s->cap < s->len) {
+        s->cap = s->len * 2;
+        s->data = (char *)realloc(s->data, s->cap);
+        assert(s->data);
+    }
+}
+
+void append(String *s, const char *data, size_t len) {
+    resize(s, s->len + len);
+    memcpy(s->data + s->len - len, data, len);
+}
+
+typedef enum { space = 0, other = 1, backslash = 2, apostrophe = 3, quotation_mark = 4 } CharClass;
+typedef enum { outside, unq, unq_esc, sq, sq_esc, dq, dq_esc } State;
+
+// current State -> CharClass -> next State
+const State transitions[][5] = {
+    [outside] = {outside, unq, unq_esc, sq,  dq},
+    [unq]     = {outside, unq, unq_esc, sq,  dq},
+    [unq_esc] = {unq,     unq, unq,     unq, unq},
+    [sq]      = {sq,      sq,  sq_esc,  unq, sq},
+    [sq_esc]  = {sq,      sq,  sq,      sq,  sq},
+    [dq]      = {dq,      dq,  dq_esc,  dq,  unq},
+    [dq_esc]  = {dq,      dq,  dq,      dq,  dq},
+};
+
+CharClass charClass(int c) {
+    return c == '\\' ? backslash : c == '\'' ? apostrophe : c == '"' ? quotation_mark :
+            isspace(c) ? space : other;
+}
+
+// expandArg writes NULL-terminated expansions of `arg', a NULL-terminated
+// string, to stdout.  If arg does not begin with `@' or does not refer to a
+// file, it is written as is.  Otherwise the contents of the file are
+// recursively expanded.  On unexpected EOF in malformed response files an
+// incomplete final argument is written, even if it is empty, to parse like GCC.
+void expandArg(String *arg) {
+    FILE *f;
+    if (arg->data[0] != '@' || !(f = fopen(&arg->data[1], "r"))) {
+        fwrite(arg->data, 1, arg->len, stdout);
+        return;
+    }
+
+    resize(arg, 0);
+    State cur = outside;
+    int c;
+    do {
+        c = fgetc(f);
+        State next = transitions[cur][charClass(c)];
+        if ((cur == unq && next == outside) || (cur != outside && c == EOF)) {
+            append(arg, "", 1);
+            expandArg(arg);
+            resize(arg, 0);
+        } else if (cur == unq_esc || cur == sq_esc || cur == dq_esc ||
+                   (cur == outside ? next == unq : cur == next)) {
+            char s = c;
+            append(arg, &s, 1);
+        }
+        cur = next;
+    } while (c != EOF);
+
+    fclose(f);
+}
+
+int main(int argc, char **argv) {
+    String arg = { 0 };
+    while (*++argv) {
+        resize(&arg, 0);
+        append(&arg, *argv, strlen(*argv) + 1);
+        expandArg(&arg);
+    }
+    free(arg.data);
+    return EXIT_SUCCESS;
+}