1 // SPDX-License-Identifier: MIT
2 /*
3 * Copyright © 2023 Intel Corporation
4 */
5
6 #define _GNU_SOURCE
7 #include <ctype.h>
8 #include <errno.h>
9 #include <stdbool.h>
10 #include <stdio.h>
11 #include <string.h>
12
13 #define HEADER \
14 "// SPDX-License-Identifier: MIT\n" \
15 "\n" \
16 "/*\n" \
17 " * DO NOT MODIFY.\n" \
18 " *\n" \
19 " * This file was generated from rules: %s\n" \
20 " */\n" \
21 "#ifndef _GENERATED_%s_\n" \
22 "#define _GENERATED_%s_\n" \
23 "\n" \
24 "enum {\n"
25
26 #define FOOTER \
27 "};\n" \
28 "\n" \
29 "#endif\n"
30
print_usage(FILE * f,const char * progname)31 static void print_usage(FILE *f, const char *progname)
32 {
33 fprintf(f, "usage: %s <input-rule-file> <generated-c-source-file> <generated-c-header-file>\n",
34 progname);
35 }
36
print_parse_error(const char * err_msg,const char * line,unsigned int lineno)37 static void print_parse_error(const char *err_msg, const char *line,
38 unsigned int lineno)
39 {
40 fprintf(stderr, "ERROR: %s\nERROR: %u: %.60s\n",
41 err_msg, lineno, line);
42 }
43
strip(char * line,size_t linelen)44 static char *strip(char *line, size_t linelen)
45 {
46 while (isspace(*(line + linelen)))
47 linelen--;
48
49 line[linelen - 1] = '\0';
50
51 return line + strspn(line, " \f\n\r\t\v");
52 }
53
54 #define MAX_LINE_LEN 4096
parse(FILE * input,FILE * csource,FILE * cheader,char * prefix)55 static int parse(FILE *input, FILE *csource, FILE *cheader, char *prefix)
56 {
57 char line[MAX_LINE_LEN + 1];
58 char *name, *prev_name = NULL, *rules;
59 unsigned int lineno = 0, idx = 0;
60
61 while (fgets(line, sizeof(line), input)) {
62 size_t linelen;
63 bool is_continuation;
64
65 if (line[0] == '\0' || line[0] == '#' || line[0] == '\n') {
66 lineno++;
67 continue;
68 }
69
70 linelen = strlen(line);
71 if (linelen == MAX_LINE_LEN) {
72 print_parse_error("line too long", line, lineno);
73 return -EINVAL;
74 }
75
76 is_continuation = isspace(line[0]);
77 name = strip(line, linelen);
78
79 if (!is_continuation) {
80 name = strtok(name, " \t");
81 rules = strtok(NULL, "");
82 } else {
83 if (!prev_name) {
84 print_parse_error("invalid rule continuation",
85 line, lineno);
86 return -EINVAL;
87 }
88
89 rules = name;
90 name = NULL;
91 }
92
93 if (rules[0] == '\0') {
94 print_parse_error("invalid empty rule\n", line, lineno);
95 return -EINVAL;
96 }
97
98 if (name) {
99 fprintf(cheader, "\t%s_%s = %u,\n", prefix, name, idx);
100
101 /* Close previous entry before starting a new one */
102 if (idx)
103 fprintf(csource, ") },\n");
104
105 fprintf(csource, "{ XE_RTP_NAME(\"%s\"),\n XE_RTP_RULES(%s",
106 name, rules);
107 idx++;
108 } else {
109 fprintf(csource, ", OR,\n\t%s", rules);
110 }
111
112 lineno++;
113 if (!is_continuation)
114 prev_name = name;
115 }
116
117 /* Close last entry */
118 if (idx)
119 fprintf(csource, ") },\n");
120
121 fprintf(cheader, "\t_%s_COUNT = %u\n", prefix, idx);
122
123 return 0;
124 }
125
126 /* Avoid GNU vs POSIX basename() discrepancy, just use our own */
xbasename(const char * s)127 static const char *xbasename(const char *s)
128 {
129 const char *p = strrchr(s, '/');
130
131 return p ? p + 1 : s;
132 }
133
fn_to_prefix(const char * fn,char * prefix,size_t size)134 static int fn_to_prefix(const char *fn, char *prefix, size_t size)
135 {
136 size_t len;
137
138 fn = xbasename(fn);
139 len = strlen(fn);
140
141 if (len > size - 1)
142 return -ENAMETOOLONG;
143
144 memcpy(prefix, fn, len + 1);
145
146 for (char *p = prefix; *p; p++) {
147 switch (*p) {
148 case '.':
149 *p = '\0';
150 return 0;
151 default:
152 *p = toupper(*p);
153 break;
154 }
155 }
156
157 return 0;
158 }
159
main(int argc,const char * argv[])160 int main(int argc, const char *argv[])
161 {
162 enum {
163 ARGS_INPUT,
164 ARGS_CSOURCE,
165 ARGS_CHEADER,
166 _ARGS_COUNT
167 };
168 struct {
169 const char *fn;
170 const char *mode;
171 FILE *f;
172 } args[] = {
173 [ARGS_INPUT] = { .fn = argv[1], .mode = "r" },
174 [ARGS_CSOURCE] = { .fn = argv[2], .mode = "w" },
175 [ARGS_CHEADER] = { .fn = argv[3], .mode = "w" },
176 };
177 int ret = 1;
178 char prefix[128];
179
180 if (argc < 3) {
181 fprintf(stderr, "ERROR: wrong arguments\n");
182 print_usage(stderr, argv[0]);
183 return 1;
184 }
185
186 if (fn_to_prefix(args[ARGS_CHEADER].fn, prefix, sizeof(prefix)) < 0)
187 return 1;
188
189 for (int i = 0; i < _ARGS_COUNT; i++) {
190 args[i].f = fopen(args[i].fn, args[i].mode);
191 if (!args[i].f) {
192 fprintf(stderr, "ERROR: Can't open %s: %m\n",
193 args[i].fn);
194 goto err;
195 }
196 }
197
198 fprintf(args[ARGS_CHEADER].f, HEADER, args[ARGS_INPUT].fn, prefix, prefix);
199
200 ret = parse(args[ARGS_INPUT].f, args[ARGS_CSOURCE].f,
201 args[ARGS_CHEADER].f, prefix);
202 if (!ret)
203 fprintf(args[ARGS_CHEADER].f, FOOTER);
204
205 err:
206 for (int i = 0; i < _ARGS_COUNT; i++) {
207 if (args[i].f)
208 fclose(args[i].f);
209 }
210
211 return ret;
212 }
213