~stub/ubuntu/trusty/avro-c/trunk

« back to all changes in this revision

Viewing changes to src/avropipe.c

  • Committer: Stuart Bishop
  • Date: 2015-05-14 11:53:53 UTC
  • Revision ID: stuart@stuartbishop.net-20150514115353-0cvnrcyohcq5l7yj
Tags: upstream-1.7.7
ImportĀ upstreamĀ versionĀ 1.7.7

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
 * http://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 <ctype.h>
 
19
#include <errno.h>
 
20
#include <getopt.h>
 
21
#include <avro/platform.h>
 
22
#include <avro/platform.h>
 
23
#include <stdio.h>
 
24
#include <stdlib.h>
 
25
#include <string.h>
 
26
 
 
27
#include "avro.h"
 
28
#include "avro_private.h"
 
29
 
 
30
 
 
31
/* The path separator to use in the JSON output. */
 
32
 
 
33
static const char  *separator = "/";
 
34
 
 
35
 
 
36
/*-- PROCESSING A FILE --*/
 
37
 
 
38
/**
 
39
 * Fills in a raw string with the path to an element of an array.
 
40
 */
 
41
 
 
42
static void
 
43
create_array_prefix(avro_raw_string_t *dest, const char *prefix, size_t index)
 
44
{
 
45
        static char  buf[100];
 
46
        snprintf(buf, sizeof(buf), "%" PRIsz, index);
 
47
        avro_raw_string_set(dest, prefix);
 
48
        avro_raw_string_append(dest, separator);
 
49
        avro_raw_string_append(dest, buf);
 
50
}
 
51
 
 
52
static void
 
53
create_object_prefix(avro_raw_string_t *dest, const char *prefix, const char *key)
 
54
{
 
55
        /*
 
56
         * Make sure that the key doesn't contain the separator
 
57
         * character.
 
58
         */
 
59
 
 
60
        if (strstr(key, separator) != NULL) {
 
61
                fprintf(stderr,
 
62
                        "Error: Element \"%s\" in object %s "
 
63
                        "contains the separator character.\n"
 
64
                        "Please use the --separator option to choose another.\n",
 
65
                        key, prefix);
 
66
                exit(1);
 
67
        }
 
68
 
 
69
        avro_raw_string_set(dest, prefix);
 
70
        avro_raw_string_append(dest, separator);
 
71
        avro_raw_string_append(dest, key);
 
72
}
 
73
 
 
74
static void
 
75
print_bytes_value(const char *buf, size_t size)
 
76
{
 
77
        size_t  i;
 
78
        printf("\"");
 
79
        for (i = 0; i < size; i++)
 
80
        {
 
81
                if (buf[i] == '"') {
 
82
                        printf("\\\"");
 
83
                } else if (buf[i] == '\\') {
 
84
                        printf("\\\\");
 
85
                } else if (buf[i] == '\b') {
 
86
                        printf("\\b");
 
87
                } else if (buf[i] == '\f') {
 
88
                        printf("\\f");
 
89
                } else if (buf[i] == '\n') {
 
90
                        printf("\\n");
 
91
                } else if (buf[i] == '\r') {
 
92
                        printf("\\r");
 
93
                } else if (buf[i] == '\t') {
 
94
                        printf("\\t");
 
95
                } else if (isprint(buf[i])) {
 
96
                        printf("%c", (int) buf[i]);
 
97
                } else {
 
98
                        printf("\\u00%02x", (unsigned int) (unsigned char) buf[i]);
 
99
                }
 
100
        }
 
101
        printf("\"");
 
102
}
 
103
 
 
104
static void
 
105
process_value(const char *prefix, avro_value_t *value);
 
106
 
 
107
static void
 
108
process_array(const char *prefix, avro_value_t *value)
 
109
{
 
110
        printf("%s\t[]\n", prefix);
 
111
        size_t  element_count;
 
112
        avro_value_get_size(value, &element_count);
 
113
 
 
114
        avro_raw_string_t  element_prefix;
 
115
        avro_raw_string_init(&element_prefix);
 
116
 
 
117
        size_t  i;
 
118
        for (i = 0; i < element_count; i++) {
 
119
                avro_value_t  element_value;
 
120
                avro_value_get_by_index(value, i, &element_value, NULL);
 
121
 
 
122
                create_array_prefix(&element_prefix, prefix, i);
 
123
                process_value((const char *) avro_raw_string_get(&element_prefix), &element_value);
 
124
        }
 
125
 
 
126
        avro_raw_string_done(&element_prefix);
 
127
}
 
128
 
 
129
static void
 
130
process_enum(const char *prefix, avro_value_t *value)
 
131
{
 
132
        int  val;
 
133
        const char  *symbol_name;
 
134
 
 
135
        avro_schema_t  schema = avro_value_get_schema(value);
 
136
        avro_value_get_enum(value, &val);
 
137
        symbol_name = avro_schema_enum_get(schema, val);
 
138
        printf("%s\t", prefix);
 
139
        print_bytes_value(symbol_name, strlen(symbol_name));
 
140
        printf("\n");
 
141
}
 
142
 
 
143
static void
 
144
process_map(const char *prefix, avro_value_t *value)
 
145
{
 
146
        printf("%s\t{}\n", prefix);
 
147
        size_t  element_count;
 
148
        avro_value_get_size(value, &element_count);
 
149
 
 
150
        avro_raw_string_t  element_prefix;
 
151
        avro_raw_string_init(&element_prefix);
 
152
 
 
153
        size_t  i;
 
154
        for (i = 0; i < element_count; i++) {
 
155
                const char  *key;
 
156
                avro_value_t  element_value;
 
157
                avro_value_get_by_index(value, i, &element_value, &key);
 
158
 
 
159
                create_object_prefix(&element_prefix, prefix, key);
 
160
                process_value((const char *) avro_raw_string_get(&element_prefix), &element_value);
 
161
        }
 
162
 
 
163
        avro_raw_string_done(&element_prefix);
 
164
}
 
165
 
 
166
static void
 
167
process_record(const char *prefix, avro_value_t *value)
 
168
{
 
169
        printf("%s\t{}\n", prefix);
 
170
        size_t  field_count;
 
171
        avro_value_get_size(value, &field_count);
 
172
 
 
173
        avro_raw_string_t  field_prefix;
 
174
        avro_raw_string_init(&field_prefix);
 
175
 
 
176
        size_t  i;
 
177
        for (i = 0; i < field_count; i++) {
 
178
                avro_value_t  field_value;
 
179
                const char  *field_name;
 
180
                avro_value_get_by_index(value, i, &field_value, &field_name);
 
181
 
 
182
                create_object_prefix(&field_prefix, prefix, field_name);
 
183
                process_value((const char *) avro_raw_string_get(&field_prefix), &field_value);
 
184
        }
 
185
 
 
186
        avro_raw_string_done(&field_prefix);
 
187
}
 
188
 
 
189
static void
 
190
process_union(const char *prefix, avro_value_t *value)
 
191
{
 
192
        avro_value_t  branch_value;
 
193
        avro_value_get_current_branch(value, &branch_value);
 
194
 
 
195
        /* nulls in a union aren't wrapped in a JSON object */
 
196
        if (avro_value_get_type(&branch_value) == AVRO_NULL) {
 
197
                printf("%s\tnull\n", prefix);
 
198
                return;
 
199
        }
 
200
 
 
201
        int  discriminant;
 
202
        avro_value_get_discriminant(value, &discriminant);
 
203
 
 
204
        avro_schema_t  schema = avro_value_get_schema(value);
 
205
        avro_schema_t  branch_schema = avro_schema_union_branch(schema, discriminant);
 
206
        const char  *branch_name = avro_schema_type_name(branch_schema);
 
207
 
 
208
        avro_raw_string_t  branch_prefix;
 
209
        avro_raw_string_init(&branch_prefix);
 
210
        create_object_prefix(&branch_prefix, prefix, branch_name);
 
211
 
 
212
        printf("%s\t{}\n", prefix);
 
213
        process_value((const char *) avro_raw_string_get(&branch_prefix), &branch_value);
 
214
 
 
215
        avro_raw_string_done(&branch_prefix);
 
216
}
 
217
 
 
218
static void
 
219
process_value(const char *prefix, avro_value_t *value)
 
220
{
 
221
        avro_type_t  type = avro_value_get_type(value);
 
222
        switch (type) {
 
223
                case AVRO_BOOLEAN:
 
224
                {
 
225
                        int  val;
 
226
                        avro_value_get_boolean(value, &val);
 
227
                        printf("%s\t%s\n", prefix, val? "true": "false");
 
228
                        return;
 
229
                }
 
230
 
 
231
                case AVRO_BYTES:
 
232
                {
 
233
                        const void  *buf;
 
234
                        size_t  size;
 
235
                        avro_value_get_bytes(value, &buf, &size);
 
236
                        printf("%s\t", prefix);
 
237
                        print_bytes_value((const char *) buf, size);
 
238
                        printf("\n");
 
239
                        return;
 
240
                }
 
241
 
 
242
                case AVRO_DOUBLE:
 
243
                {
 
244
                        double  val;
 
245
                        avro_value_get_double(value, &val);
 
246
                        printf("%s\t%lf\n", prefix, val);
 
247
                        return;
 
248
                }
 
249
 
 
250
                case AVRO_FLOAT:
 
251
                {
 
252
                        float  val;
 
253
                        avro_value_get_float(value, &val);
 
254
                        printf("%s\t%f\n", prefix, val);
 
255
                        return;
 
256
                }
 
257
 
 
258
                case AVRO_INT32:
 
259
                {
 
260
                        int32_t  val;
 
261
                        avro_value_get_int(value, &val);
 
262
                        printf("%s\t%" PRId32 "\n", prefix, val);
 
263
                        return;
 
264
                }
 
265
 
 
266
                case AVRO_INT64:
 
267
                {
 
268
                        int64_t  val;
 
269
                        avro_value_get_long(value, &val);
 
270
                        printf("%s\t%" PRId64 "\n", prefix, val);
 
271
                        return;
 
272
                }
 
273
 
 
274
                case AVRO_NULL:
 
275
                {
 
276
                        avro_value_get_null(value);
 
277
                        printf("%s\tnull\n", prefix);
 
278
                        return;
 
279
                }
 
280
 
 
281
                case AVRO_STRING:
 
282
                {
 
283
                        /* TODO: Convert the UTF-8 to the current
 
284
                         * locale's character set */
 
285
                        const char  *buf;
 
286
                        size_t  size;
 
287
                        avro_value_get_string(value, &buf, &size);
 
288
                        printf("%s\t", prefix);
 
289
                        /* For strings, size includes the NUL terminator. */
 
290
                        print_bytes_value(buf, size-1);
 
291
                        printf("\n");
 
292
                        return;
 
293
                }
 
294
 
 
295
                case AVRO_ARRAY:
 
296
                        process_array(prefix, value);
 
297
                        return;
 
298
 
 
299
                case AVRO_ENUM:
 
300
                        process_enum(prefix, value);
 
301
                        return;
 
302
 
 
303
                case AVRO_FIXED:
 
304
                {
 
305
                        const void  *buf;
 
306
                        size_t  size;
 
307
                        avro_value_get_fixed(value, &buf, &size);
 
308
                        printf("%s\t", prefix);
 
309
                        print_bytes_value((const char *) buf, size);
 
310
                        printf("\n");
 
311
                        return;
 
312
                }
 
313
 
 
314
                case AVRO_MAP:
 
315
                        process_map(prefix, value);
 
316
                        return;
 
317
 
 
318
                case AVRO_RECORD:
 
319
                        process_record(prefix, value);
 
320
                        return;
 
321
 
 
322
                case AVRO_UNION:
 
323
                        process_union(prefix, value);
 
324
                        return;
 
325
 
 
326
                default:
 
327
                {
 
328
                        fprintf(stderr, "Unknown schema type\n");
 
329
                        exit(1);
 
330
                }
 
331
        }
 
332
}
 
333
 
 
334
static void
 
335
process_file(const char *filename)
 
336
{
 
337
        avro_file_reader_t  reader;
 
338
 
 
339
        if (filename == NULL) {
 
340
                if (avro_file_reader_fp(stdin, "<stdin>", 0, &reader)) {
 
341
                        fprintf(stderr, "Error opening <stdin>:\n  %s\n",
 
342
                                avro_strerror());
 
343
                        exit(1);
 
344
                }
 
345
        } else {
 
346
                if (avro_file_reader(filename, &reader)) {
 
347
                        fprintf(stderr, "Error opening %s:\n  %s\n",
 
348
                                filename, avro_strerror());
 
349
                        exit(1);
 
350
                }
 
351
        }
 
352
 
 
353
        /* The JSON root is an array */
 
354
        printf("%s\t[]\n", separator);
 
355
 
 
356
        avro_raw_string_t  prefix;
 
357
        avro_raw_string_init(&prefix);
 
358
 
 
359
        avro_schema_t  wschema = avro_file_reader_get_writer_schema(reader);
 
360
        avro_value_iface_t  *iface = avro_generic_class_from_schema(wschema);
 
361
        avro_value_t  value;
 
362
        avro_generic_value_new(iface, &value);
 
363
 
 
364
        size_t  record_number = 0;
 
365
        int rval;
 
366
 
 
367
        for (; (rval = avro_file_reader_read_value(reader, &value)) == 0; record_number++) {
 
368
                create_array_prefix(&prefix, "", record_number);
 
369
                process_value((const char *) avro_raw_string_get(&prefix), &value);
 
370
                avro_value_reset(&value);
 
371
        }
 
372
 
 
373
        if (rval != EOF) {
 
374
                fprintf(stderr, "Error reading value: %s", avro_strerror());
 
375
        }
 
376
 
 
377
        avro_raw_string_done(&prefix);
 
378
        avro_value_decref(&value);
 
379
        avro_value_iface_decref(iface);
 
380
        avro_file_reader_close(reader);
 
381
        avro_schema_decref(wschema);
 
382
}
 
383
 
 
384
 
 
385
/*-- MAIN PROGRAM --*/
 
386
static struct option longopts[] = {
 
387
        { "separator", required_argument, NULL, 's' },
 
388
        { NULL, 0, NULL, 0 }
 
389
};
 
390
 
 
391
static void usage(void)
 
392
{
 
393
        fprintf(stderr,
 
394
                "Usage: avropipe [--separator=<separator>]\n"
 
395
                "                <avro data file>\n");
 
396
}
 
397
 
 
398
 
 
399
int main(int argc, char **argv)
 
400
{
 
401
        char  *data_filename;
 
402
 
 
403
        int  ch;
 
404
        while ((ch = getopt_long(argc, argv, "s:", longopts, NULL) ) != -1) {
 
405
                switch (ch) {
 
406
                        case 's':
 
407
                                separator = optarg;
 
408
                                break;
 
409
 
 
410
                        default:
 
411
                                usage();
 
412
                                exit(1);
 
413
                }
 
414
        }
 
415
 
 
416
        argc -= optind;
 
417
        argv += optind;
 
418
 
 
419
        if (argc == 1) {
 
420
                data_filename = argv[0];
 
421
        } else if (argc == 0) {
 
422
                data_filename = NULL;
 
423
        } else {
 
424
                fprintf(stderr, "Can't read from multiple input files.\n");
 
425
                usage();
 
426
                exit(1);
 
427
        }
 
428
 
 
429
        /* Process the data file */
 
430
        process_file(data_filename);
 
431
        return 0;
 
432
}