1/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <getopt.h>
18#include <stdio.h>
19#include <stdlib.h>
20#include <string.h>
21#include <unistd.h>
22
23/*
24 * The parameters to generate testing DTS
25 * /dts-v1/ /plugin/;           <- header and plugin
26 * /{
27 *   level0 {                   <- depth
28 *     level1 {
29 *       ...
30 *       node0: node0 {         <- node
31 *         unused0 {}           <- unused
32 *         unused1 {}
33 *         ...
34 *         status="disabled";
35 *       }
36 *       ...
37 *     };
38 *   };
39 * };
40 *
41 * &node0 {                     <- append
42 *    new_prop="foo";
43 * }
44 * ...
45 *
46 * &node0 {                     <- override
47 *    status="okay";
48 * }
49 * ...
50 */
51
52static const char short_options[] = "Hpd:u:n:a:w:o:";
53static struct option long_options[] = {
54  { "no-header",    no_argument,       NULL, 'H' },
55  { "plugin",       no_argument,       NULL, 'p' },
56  { "depth",        required_argument, NULL, 'd' },
57  { "unused",       required_argument, NULL, 'u' },
58  { "node",         required_argument, NULL, 'n' },
59  { "append",       required_argument, NULL, 'a' },
60  { "override",     required_argument, NULL, 'w' },
61  { "output",       required_argument, NULL, 'o' },
62  { 0,              0,                 NULL, 0 }
63};
64
65struct gen_params {
66  int no_header;    /* Doesn't add header */
67  int plugin;       /* Add /plugin/ in header */
68  int depth;        /* the depth of a node, 0 means generate on root node */
69  int unused_num;   /* unused child nodes per node */
70  int node_num;     /* the number to generate nodes */
71  int append_num;   /* the number to generate appending references */
72  int override_num; /* the number to generate overriding references */
73};
74
75
76static void output_header(FILE *fp, int is_plugin) {
77  fprintf(fp, "/dts-v1/;\n");
78  if (is_plugin) {
79    fprintf(fp, "/plugin/;\n");
80  }
81  fprintf(fp, "\n");
82}
83
84static void output_root_begin(FILE *fp, int depth) {
85  fprintf(fp, "/ {\n");
86
87  int i;
88  for (i = 0; i < depth; i++) {
89    fprintf(fp, "level%d {\n", i);
90  }
91}
92
93static void output_root_end(FILE *fp, int depth) {
94  int i;
95  for (i = 0; i < depth; i++) {
96    fprintf(fp, "};\n");
97  }
98
99  fprintf(fp, "};\n\n");
100}
101
102static void output_unused_nodes(FILE *fp, int count) {
103  int i;
104  for (i = 0; i < count; i++) {
105    fprintf(fp, "unused%d {};\n", i);
106  }
107}
108
109static void output_prop_str(FILE *fp, const char *prop, const char *value) {
110  /* TODO: should escape value */
111  fprintf(fp, "%s=\"%s\";\n", prop, value);
112}
113
114static void output_nodes(FILE *fp, int count, const char *prop, const char *value) {
115  int i;
116  for (i = 0; i < count; i++) {
117    fprintf(fp, "node%d: node%d {\n", i, i);
118    output_prop_str(fp, prop, value);
119    fprintf(fp, "};\n\n");
120  }
121}
122
123static void output_ref_nodes(FILE *fp, int start_id, int count,
124                      const char *prop, const char *value) {
125  int i;
126  for (i = start_id; i < start_id + count; i++) {
127    fprintf(fp, "&node%d {\n", i);
128    output_prop_str(fp, prop, value);
129    fprintf(fp, "};\n\n");
130  }
131}
132
133static int gen_dts(FILE *fp, const struct gen_params *params) {
134  if (!params->no_header) {
135    output_header(fp, params->plugin);
136  }
137
138  if (params->node_num > 0) {
139    output_root_begin(fp, params->depth);
140    output_unused_nodes(fp, params->unused_num);
141    output_nodes(fp, params->node_num, "status", "disabled");
142    output_root_end(fp, params->depth);
143  }
144
145  int start_id = 0;
146  output_ref_nodes(fp, start_id, params->append_num, "new_prop", "bar");
147  start_id += params->append_num;
148  output_ref_nodes(fp, start_id, params->override_num, "status", "okay");
149
150  return 0;
151}
152
153int main(int argc, char *argv[]) {
154  const char *filename = NULL;
155  struct gen_params params;
156  memset(&params, 0, sizeof(struct gen_params));
157
158  while (1) {
159    int option_index = 0;
160    int c = getopt_long(argc, argv, short_options, long_options, &option_index);
161    if (c == -1) {
162      break;
163    }
164    switch (c) {
165    case 'H':
166      params.no_header = 1;
167      break;
168    case 'p':
169      params.plugin = 1;
170      break;
171    case 'd':
172      params.depth = atoi(optarg);
173      break;
174    case 'u':
175      params.unused_num = atoi(optarg);
176      break;
177    case 'n':
178      params.node_num = atoi(optarg);
179      break;
180    case 'a':
181      params.append_num = atoi(optarg);
182      break;
183    case 'w':
184      params.override_num = atoi(optarg);
185      break;
186    case 'o':
187      filename = optarg;
188      break;
189    case '?':
190      break;
191    }
192  }
193
194  FILE *fp = NULL;
195  if (filename) {
196    fp = fopen(filename, "wt");
197    if (fp == NULL) {
198      fprintf(stderr, "Can not create file: ", filename);
199      return -1;
200    }
201  }
202
203  gen_dts(fp ? fp : stdout, &params);
204
205  if (fp) {
206    fclose(fp);
207  }
208
209  return 0;
210}
211