pytrainer: unpin python 3.10
[NixPkgs.git] / pkgs / build-support / expand-response-params / expand-response-params.c
blob05b9c62b1e8d5ea04f4d10b8f8d1fb0cf2f5ddf7
1 #include <assert.h>
2 #include <ctype.h>
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <string.h>
7 typedef struct { char *data; size_t len, cap; } String;
9 void resize(String *s, size_t len) {
10 s->len = len;
11 if (s->cap < s->len) {
12 s->cap = s->len * 2;
13 s->data = (char *)realloc(s->data, s->cap);
14 assert(s->data);
18 void append(String *s, const char *data, size_t len) {
19 resize(s, s->len + len);
20 memcpy(s->data + s->len - len, data, len);
23 typedef enum { space = 0, other = 1, backslash = 2, apostrophe = 3, quotation_mark = 4 } CharClass;
24 typedef enum { outside, unq, unq_esc, sq, sq_esc, dq, dq_esc } State;
26 // current State -> CharClass -> next State
27 const State transitions[][5] = {
28 [outside] = {outside, unq, unq_esc, sq, dq},
29 [unq] = {outside, unq, unq_esc, sq, dq},
30 [unq_esc] = {unq, unq, unq, unq, unq},
31 [sq] = {sq, sq, sq_esc, unq, sq},
32 [sq_esc] = {sq, sq, sq, sq, sq},
33 [dq] = {dq, dq, dq_esc, dq, unq},
34 [dq_esc] = {dq, dq, dq, dq, dq},
37 CharClass charClass(int c) {
38 return c == '\\' ? backslash : c == '\'' ? apostrophe : c == '"' ? quotation_mark :
39 isspace(c) ? space : other;
42 // expandArg writes NULL-terminated expansions of `arg', a NULL-terminated
43 // string, to stdout. If arg does not begin with `@' or does not refer to a
44 // file, it is written as is. Otherwise the contents of the file are
45 // recursively expanded. On unexpected EOF in malformed response files an
46 // incomplete final argument is written, even if it is empty, to parse like GCC.
47 void expandArg(String *arg) {
48 FILE *f;
49 if (arg->data[0] != '@' || !(f = fopen(&arg->data[1], "r"))) {
50 fwrite(arg->data, 1, arg->len, stdout);
51 return;
54 resize(arg, 0);
55 State cur = outside;
56 int c;
57 do {
58 c = fgetc(f);
59 State next = transitions[cur][charClass(c)];
60 if ((cur == unq && next == outside) || (cur != outside && c == EOF)) {
61 append(arg, "", 1);
62 expandArg(arg);
63 resize(arg, 0);
64 } else if (cur == unq_esc || cur == sq_esc || cur == dq_esc ||
65 (cur == outside ? next == unq : cur == next)) {
66 char s = c;
67 append(arg, &s, 1);
69 cur = next;
70 } while (c != EOF);
72 fclose(f);
75 int main(int argc, char **argv) {
76 String arg = { 0 };
77 while (*++argv) {
78 resize(&arg, 0);
79 append(&arg, *argv, strlen(*argv) + 1);
80 expandArg(&arg);
82 free(arg.data);
83 return EXIT_SUCCESS;