1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements.  See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to you under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License.  You may obtain a copy of the License at
8  *
9  * https://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
14  * implied.  See the License for the specific language governing
15  * permissions and limitations under the License.
16  */
17 
18 #include "avro_private.h"
19 #include <stdio.h>
20 #include <errno.h>
21 #include <string.h>
22 
23 #include "schema.h"
24 
25 enum specific_state {
26 	START_STATE,
27 };
28 typedef enum specific_state specific_state;
29 
30 struct specific_ctx {
31 	FILE *header;
32 	FILE *source;
33 	int depth;
34 	specific_state state;
35 };
36 typedef struct specific_ctx specific_ctx;
37 
indent(specific_ctx * ctx,FILE * fp)38 static void indent(specific_ctx * ctx, FILE * fp)
39 {
40 	int i;
41 	for (i = 0; i < ctx->depth; i++) {
42 		fprintf(fp, "   ");
43 	}
44 }
45 
avro_schema_to_source(avro_schema_t schema,specific_ctx * ctx)46 static int avro_schema_to_source(avro_schema_t schema, specific_ctx * ctx)
47 {
48 	switch (schema->type) {
49 	default:
50 		return 0;
51 	}
52 	return EINVAL;
53 }
54 
avro_schema_to_header(avro_schema_t schema,specific_ctx * ctx)55 static int avro_schema_to_header(avro_schema_t schema, specific_ctx * ctx)
56 {
57 	size_t i;
58 	FILE *fp = ctx->header;
59 
60 	indent(ctx, fp);
61 	ctx->depth++;
62 
63 	if (is_avro_primitive(schema) && !ctx->name) {
64 		return 0;
65 	}
66 
67 	switch (schema->type) {
68 	case AVRO_STRING:
69 		fprintf(fp, "char *%s;\n", ctx->name);
70 		break;
71 
72 	case AVRO_BYTES:
73 		fprintf(fp, "struct %s { size_t %s_len; char *%s_val } %s;\n",
74 			ctx->name, ctx->name, ctx->name, ctx->name);
75 		break;
76 
77 	case AVRO_INT:
78 		fprintf(fp, "int %s;\n", ctx->name);
79 		break;
80 
81 	case AVRO_LONG:
82 		fprintf(fp, "long %s;\n", ctx->name);
83 		break;
84 
85 	case AVRO_FLOAT:
86 		fprintf(fp, "float %s;\n", ctx->name);
87 		break;
88 
89 	case AVRO_DOUBLE:
90 		fprintf(fp, "double %s;\n", ctx->name);
91 		break;
92 
93 	case AVRO_BOOLEAN:
94 		fprintf(fp, "int %s; /* boolean */\n", ctx->name);
95 		break;
96 
97 	case AVRO_NULL:
98 		break;
99 
100 	case AVRO_RECORD:
101 		{
102 			struct schema_record_t *record_schema =
103 			    avro_schema_to_record(schema);
104 			fprintf(fp, "struct %s {\n", record_schema->name);
105 			for (i = 0; i < record_schema->num_fields; i++) {
106 				struct record_field_t *field =
107 				    record_schema->fields[i];
108 				ctx->name = field->name;
109 				avro_schema_to_header(field->type, ctx);
110 				ctx->name = NULL;
111 			}
112 			fprintf(fp, "};\n");
113 			fprintf(fp, "typedef struct %s %s;\n\n",
114 				record_schema->name, record_schema->name);
115 		}
116 		break;
117 
118 	case AVRO_ENUM:
119 		{
120 			struct schema_enum_t *enum_schema =
121 			    avro_schema_to_enum(schema);
122 			fprintf(fp, "enum %s {\n", enum_schema->name);
123 			ctx->depth++;
124 			for (i = 0; i < enum_schema->num_symbols; i++) {
125 				indent(ctx, fp);
126 				fprintf(fp, "%s = %ld,\n",
127 					enum_schema->symbols[i], i);
128 			}
129 			ctx->depth--;
130 			fprintf(fp, "};\n");
131 			fprintf(fp, "typedef enum %s %s;\n\n",
132 				enum_schema->name, enum_schema->name);
133 		}
134 		break;
135 
136 	case AVRO_FIXED:
137 		{
138 			struct schema_fixed_t *fixed_schema =
139 			    avro_schema_to_fixed(schema);
140 			fprintf(fp, "char %s[%ld];\n", fixed_schema->name,
141 				fixed_schema->size);
142 		}
143 		break;
144 
145 	case AVRO_MAP:
146 		{
147 
148 		}
149 		break;
150 
151 	case AVRO_ARRAY:
152 		{
153 			struct schema_array_t *array_schema =
154 			    avro_schema_to_array(schema);
155 			if (!ctx->name) {
156 				break;
157 			}
158 			fprintf(fp, "struct { size_t %s_len; ", ctx->name);
159 			if (is_avro_named_type(array_schema->items)) {
160 				fprintf(fp, "%s",
161 					avro_schema_name(array_schema->items));
162 			} else if (is_avro_link(array_schema->items)) {
163 				struct schema_link_t *link_schema =
164 				    avro_schema_to_link(array_schema->items);
165 				fprintf(fp, "struct %s",
166 					avro_schema_name(link_schema->to));
167 			} else {
168 				avro_schema_to_header(array_schema->items, ctx);
169 			}
170 			fprintf(fp, " *%s_val;} %s;\n", ctx->name, ctx->name);
171 		}
172 		break;
173 	case AVRO_UNION:
174 		{
175 			struct schema_union_t *union_schema =
176 			    avro_schema_to_array(schema);
177 			if (!ctx->name) {
178 				break;
179 			}
180 			fprintf(fp, "union {\n");
181 			for (i = 0; i < union_schema->num_schemas; i++) {
182 				avro_schema_to_header(union_schema->schemas[i],
183 						      ctx);
184 			}
185 			fprintf(fp, "%s_u;\n");
186 		}
187 		break;
188 	case AVRO_LINK:
189 		break;
190 	default:
191 		return EINVAL;
192 	}
193 
194 	ctx->depth--;
195 	return 0;
196 }
197 
avro_schema_to_specific(avro_schema_t schema,const char * prefix)198 int avro_schema_to_specific(avro_schema_t schema, const char *prefix)
199 {
200 	specific_ctx ctx;
201 	char buf[1024];
202 	int rval;
203 
204 	if (!schema) {
205 		return EINVAL;
206 	}
207 
208 	memset(&ctx, 0, sizeof(ctx));
209 	snprintf(buf, sizeof(buf), "%s_avro.h", prefix);
210 	ctx.header = fopen(buf, "w");
211 	if (!ctx.header) {
212 		return errno;
213 	}
214 	snprintf(buf, sizeof(buf), "%s_avro.c", prefix);
215 	ctx.source = fopen(buf, "w");
216 	if (!ctx.source) {
217 		fclose(ctx.header);
218 		return errno;
219 	}
220 
221 	rval = avro_schema_to_header(schema, &ctx);
222 	if (rval) {
223 		goto out;
224 	}
225 
226 	rval = avro_schema_to_source(schema, &ctx);
227 
228       out:
229 	fclose(ctx.header);
230 	fclose(ctx.source);
231 	return rval;
232 }
233