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 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 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 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 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 */ 127 static const char *xbasename(const char *s) 128 { 129 const char *p = strrchr(s, '/'); 130 131 return p ? p + 1 : s; 132 } 133 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 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