Mercurial > hg > piper-cpp
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 } |