comparison ext/serd/src/serdi.c @ 247:8a031eb9a25f

Merge branch 'output-type-uri'
author Chris Cannam <cannam@all-day-breakfast.com>
date Thu, 15 Jun 2017 09:52:01 +0100
parents c5cdc9e6a4bf
children
comparison
equal deleted inserted replaced
219:db929669e7d3 247:8a031eb9a25f
1 /*
2 Copyright 2011-2017 David Robillard <http://drobilla.net>
3
4 Permission to use, copy, modify, and/or distribute this software for any
5 purpose with or without fee is hereby granted, provided that the above
6 copyright notice and this permission notice appear in all copies.
7
8 THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17 #include "serd_internal.h"
18
19 #include <assert.h>
20 #include <errno.h>
21 #include <stdlib.h>
22 #include <string.h>
23
24 #define SERDI_ERROR(msg) fprintf(stderr, "serdi: " msg);
25 #define SERDI_ERRORF(fmt, ...) fprintf(stderr, "serdi: " fmt, __VA_ARGS__);
26
27 static int
28 print_version(void)
29 {
30 printf("serdi " SERD_VERSION " <http://drobilla.net/software/serd>\n");
31 printf("Copyright 2011-2017 David Robillard <http://drobilla.net>.\n"
32 "License: <http://www.opensource.org/licenses/isc>\n"
33 "This is free software; you are free to change and redistribute it."
34 "\nThere is NO WARRANTY, to the extent permitted by law.\n");
35 return 0;
36 }
37
38 static int
39 print_usage(const char* name, bool error)
40 {
41 FILE* const os = error ? stderr : stdout;
42 fprintf(os, "%s", error ? "\n" : "");
43 fprintf(os, "Usage: %s [OPTION]... INPUT [BASE_URI]\n", name);
44 fprintf(os, "Read and write RDF syntax.\n");
45 fprintf(os, "Use - for INPUT to read from standard input.\n\n");
46 fprintf(os, " -b Fast bulk output for large serialisations.\n");
47 fprintf(os, " -c PREFIX Chop PREFIX from matching blank node IDs.\n");
48 fprintf(os, " -e Eat input one character at a time.\n");
49 fprintf(os, " -f Keep full URIs in input (don't qualify).\n");
50 fprintf(os, " -h Display this help and exit.\n");
51 fprintf(os, " -i SYNTAX Input syntax: turtle/ntriples/trig/nquads.\n");
52 fprintf(os, " -l Lax (non-strict) parsing.\n");
53 fprintf(os, " -o SYNTAX Output syntax: turtle/ntriples/nquads.\n");
54 fprintf(os, " -p PREFIX Add PREFIX to blank node IDs.\n");
55 fprintf(os, " -q Suppress all output except data.\n");
56 fprintf(os, " -r ROOT_URI Keep relative URIs within ROOT_URI.\n");
57 fprintf(os, " -s INPUT Parse INPUT as string (terminates options).\n");
58 fprintf(os, " -v Display version information and exit.\n");
59 return error ? 1 : 0;
60 }
61
62 static bool
63 set_syntax(SerdSyntax* syntax, const char* name)
64 {
65 if (!strcmp(name, "turtle")) {
66 *syntax = SERD_TURTLE;
67 } else if (!strcmp(name, "ntriples")) {
68 *syntax = SERD_NTRIPLES;
69 } else if (!strcmp(name, "nquads")) {
70 *syntax = SERD_NQUADS;
71 } else if (!strcmp(name, "trig")) {
72 *syntax = SERD_TRIG;
73 } else {
74 SERDI_ERRORF("unknown syntax `%s'\n", name);
75 return false;
76 }
77 return true;
78 }
79
80 static int
81 missing_arg(const char* name, char opt)
82 {
83 SERDI_ERRORF("option requires an argument -- '%c'\n", opt);
84 return print_usage(name, true);
85 }
86
87 static SerdStatus
88 quiet_error_sink(void* handle, const SerdError* e)
89 {
90 return SERD_SUCCESS;
91 }
92
93 int
94 main(int argc, char** argv)
95 {
96 if (argc < 2) {
97 return print_usage(argv[0], true);
98 }
99
100 FILE* in_fd = NULL;
101 SerdSyntax input_syntax = SERD_TURTLE;
102 SerdSyntax output_syntax = SERD_NTRIPLES;
103 bool from_file = true;
104 bool bulk_read = true;
105 bool bulk_write = false;
106 bool full_uris = false;
107 bool lax = false;
108 bool quiet = false;
109 const uint8_t* in_name = NULL;
110 const uint8_t* add_prefix = NULL;
111 const uint8_t* chop_prefix = NULL;
112 const uint8_t* root_uri = NULL;
113 int a = 1;
114 for (; a < argc && argv[a][0] == '-'; ++a) {
115 if (argv[a][1] == '\0') {
116 in_name = (const uint8_t*)"(stdin)";
117 in_fd = stdin;
118 break;
119 } else if (argv[a][1] == 'b') {
120 bulk_write = true;
121 } else if (argv[a][1] == 'e') {
122 bulk_read = false;
123 } else if (argv[a][1] == 'f') {
124 full_uris = true;
125 } else if (argv[a][1] == 'h') {
126 return print_usage(argv[0], false);
127 } else if (argv[a][1] == 'l') {
128 lax = true;
129 } else if (argv[a][1] == 'q') {
130 quiet = true;
131 } else if (argv[a][1] == 'v') {
132 return print_version();
133 } else if (argv[a][1] == 's') {
134 in_name = (const uint8_t*)"(string)";
135 from_file = false;
136 ++a;
137 break;
138 } else if (argv[a][1] == 'i') {
139 if (++a == argc) {
140 return missing_arg(argv[0], 'i');
141 } else if (!set_syntax(&input_syntax, argv[a])) {
142 return print_usage(argv[0], true);
143 }
144 } else if (argv[a][1] == 'o') {
145 if (++a == argc) {
146 return missing_arg(argv[0], 'o');
147 } else if (!set_syntax(&output_syntax, argv[a])) {
148 return print_usage(argv[0], true);
149 }
150 } else if (argv[a][1] == 'p') {
151 if (++a == argc) {
152 return missing_arg(argv[0], 'p');
153 }
154 add_prefix = (const uint8_t*)argv[a];
155 } else if (argv[a][1] == 'c') {
156 if (++a == argc) {
157 return missing_arg(argv[0], 'c');
158 }
159 chop_prefix = (const uint8_t*)argv[a];
160 } else if (argv[a][1] == 'r') {
161 if (++a == argc) {
162 return missing_arg(argv[0], 'r');
163 }
164 root_uri = (const uint8_t*)argv[a];
165 } else {
166 SERDI_ERRORF("invalid option -- '%s'\n", argv[a] + 1);
167 return print_usage(argv[0], true);
168 }
169 }
170
171 if (a == argc) {
172 SERDI_ERROR("missing input\n");
173 return 1;
174 }
175
176 const uint8_t* input = (const uint8_t*)argv[a++];
177 if (from_file) {
178 in_name = in_name ? in_name : input;
179 if (!in_fd) {
180 input = serd_uri_to_path(in_name);
181 if (!input || !(in_fd = serd_fopen((const char*)input, "r"))) {
182 return 1;
183 }
184 }
185 }
186
187 SerdURI base_uri = SERD_URI_NULL;
188 SerdNode base = SERD_NODE_NULL;
189 if (a < argc) { // Base URI given on command line
190 base = serd_node_new_uri_from_string(
191 (const uint8_t*)argv[a], NULL, &base_uri);
192 } else if (from_file && in_fd != stdin) { // Use input file URI
193 base = serd_node_new_file_uri(input, NULL, &base_uri, true);
194 }
195
196 FILE* out_fd = stdout;
197 SerdEnv* env = serd_env_new(&base);
198
199 int output_style = 0;
200 if (output_syntax == SERD_NTRIPLES || output_syntax == SERD_NQUADS) {
201 output_style |= SERD_STYLE_ASCII;
202 } else if (output_syntax == SERD_TURTLE) {
203 output_style |= SERD_STYLE_ABBREVIATED;
204 if (!full_uris) {
205 output_style |= SERD_STYLE_CURIED;
206 }
207 }
208
209 if ((input_syntax == SERD_TURTLE || input_syntax == SERD_TRIG) ||
210 (output_style & SERD_STYLE_CURIED)) {
211 // Base URI may change and/or we're abbreviating URIs, so must resolve
212 output_style |= SERD_STYLE_RESOLVED;
213 }
214
215 if (bulk_write) {
216 output_style |= SERD_STYLE_BULK;
217 }
218
219 SerdWriter* writer = serd_writer_new(
220 output_syntax, (SerdStyle)output_style,
221 env, &base_uri, serd_file_sink, out_fd);
222
223 SerdReader* reader = serd_reader_new(
224 input_syntax, writer, NULL,
225 (SerdBaseSink)serd_writer_set_base_uri,
226 (SerdPrefixSink)serd_writer_set_prefix,
227 (SerdStatementSink)serd_writer_write_statement,
228 (SerdEndSink)serd_writer_end_anon);
229
230 serd_reader_set_strict(reader, !lax);
231 if (quiet) {
232 serd_reader_set_error_sink(reader, quiet_error_sink, NULL);
233 serd_writer_set_error_sink(writer, quiet_error_sink, NULL);
234 }
235
236 SerdNode root = serd_node_from_string(SERD_URI, root_uri);
237 serd_writer_set_root_uri(writer, &root);
238 serd_writer_chop_blank_prefix(writer, chop_prefix);
239 serd_reader_add_blank_prefix(reader, add_prefix);
240
241 SerdStatus status = SERD_SUCCESS;
242 if (!from_file) {
243 status = serd_reader_read_string(reader, input);
244 } else if (bulk_read) {
245 status = serd_reader_read_file_handle(reader, in_fd, in_name);
246 } else {
247 status = serd_reader_start_stream(reader, in_fd, in_name, false);
248 while (!status) {
249 status = serd_reader_read_chunk(reader);
250 }
251 serd_reader_end_stream(reader);
252 }
253
254 serd_reader_free(reader);
255 serd_writer_finish(writer);
256 serd_writer_free(writer);
257 serd_env_free(env);
258 serd_node_free(&base);
259
260 if (from_file) {
261 fclose(in_fd);
262 }
263
264 if (fclose(out_fd)) {
265 perror("serdi: write error");
266 status = SERD_ERR_UNKNOWN;
267 }
268
269 return (status > SERD_FAILURE) ? 1 : 0;
270 }