okra | C99 URI parser library. |
| download: http://git.y1.nz/archives/okra.tar.gz | |
| README | Files | Log | Refs |
base.c
1 /* This file contains the core parser functionality, primarily */
2 /* translated from the ABNF given in appendix A of [RFC3986]. */
3
4 #include <stdlib.h> /* malloc/calloc */
5 #include <assert.h> /* assert */
6 #include <stdio.h> /* printf */
7 #include <string.h> /* strcpy, strlen */
8
9 #include "okra.h"
10
11 /* parser-internal data shapes */
12 typedef struct {
13 int start;
14 int end;
15 } OkraStringPiece;
16
17 typedef struct {
18 OkraStringPiece *value;
19 OkraStringPiece *userinfo;
20 OkraStringPiece *host;
21 OkraStringPiece *port;
22 } OkraAuthorityComponent;
23
24 typedef struct {
25 OkraStringPiece *value;
26
27 // TODO: this
28 // OkraVector /* OkraStringPiece */ segments;
29 // OkraStringPiece *segments[MAX_SEGMENT_COUNT];
30 } OkraPathComponent;
31
32 typedef struct {
33 /* reference to the original input buffer. */
34 const char *buffer;
35
36 /* data that is populated as the URI is constructed, */
37 /* all NULLable. */
38 OkraStringPiece *value;
39 OkraStringPiece *scheme;
40 OkraAuthorityComponent *authority;
41 OkraPathComponent *path;
42 OkraStringPiece *query;
43 OkraStringPiece *fragment;
44 } OkraRawUri;
45
46 typedef struct {
47 OkraAuthorityComponent *authority;
48 OkraPathComponent *path;
49 } OkraRelativePart;
50
51 #define DEF_SINGLE(name, cond) \
52 int \
53 name(const char *s, int i) \
54 { \
55 return (cond) ? i+1 : -1; \
56 }
57
58 #define RANGE(lo, c, hi) (lo <= c && c <= hi)
59 #define IS_DIGIT(c) (c >= '0' && c <= '9')
60 #define IS_ALPHA(c) (RANGE('a', c, 'z') || RANGE('A', c, 'Z'))
61 #define IS_HEXDIG(c) (IS_DIGIT(c) || RANGE('a', c, 'f') || RANGE('A', c, 'F'))
62 #define IS_GEN_DELIM(c) ( \
63 s[i] == ':' || s[i] == '/' || s[i] == '?' || s[i] == '#' || \
64 s[i] == '[' || s[i] == ']' || s[i] == '@' \
65 )
66 #define IS_SUB_DELIM(c) ( \
67 s[i] == '!' || s[i] == '$' || s[i] == '&' || s[i] == '\'' || \
68 s[i] == '(' || s[i] == ')' || s[i] == '*' || s[i] == '+' || \
69 s[i] == ',' || s[i] == ';' || s[i] == '=' \
70 )
71 #define IS_UNRESERVED(c) ( \
72 (s[i] == '-' || s[i] == '.' || s[i] == '_' || s[i] == '~') || \
73 IS_ALPHA(s[i]) || IS_DIGIT(s[i]) \
74 )
75 #define IS_RESERVED(c) (IS_GEN_DELIM(s[i]) || IS_SUB_DELIM(s[i]))
76
77 int okra_parse_digit(const char *s, int i) { return IS_DIGIT(s[i]) ? i+1 : -1; }
78 int okra_parse_alpha(const char *s, int i) { return IS_ALPHA(s[i]) ? i+1 : -1; }
79 int okra_parse_hexdig(const char *s, int i) { return IS_HEXDIG(s[i]) ? i+1 : -1; }
80 int okra_parse_gen_delim(const char *s, int i) {
81 return IS_GEN_DELIM(s[i]) ? i+1 : -1;
82 }
83 int okra_parse_sub_delim(const char *s, int i) {
84 return IS_SUB_DELIM(s[i]) ? i+1 : -1;
85 }
86
87 int okra_parse_unreserved(const char *s, int i) {
88 return IS_UNRESERVED(s[i]) ? i+1 : -1;
89 }
90 int okra_parse_reserved(const char *s, int i) {
91 return IS_RESERVED(s[i]) ? i+1 : -1;
92 }
93 int okra_parse_pct_encoded(const char *s, int i) {
94 return (
95 s[i] == '%' && IS_HEXDIG(s[i+1]) && IS_HEXDIG(s[i+2])
96 ) ? i+3 : -1;
97 }
98
99 int
100 okra_parse_pchar(const char *s, int i)
101 {
102 int ret = okra_parse_unreserved(s, i);
103 if (ret == -1) ret = okra_parse_pct_encoded(s, i);
104 if (ret == -1) ret = okra_parse_sub_delim(s, i);
105 if (ret == -1) ret = (s[i] == ':' || s[i] == '@') ? i+1 : -1;
106 return ret;
107 }
108
109 OkraStringPiece *
110 okra_parse_fragment(const char *s, int i)
111 {
112 OkraStringPiece *ret = NULL;
113
114 int current = i, next;
115 for (;;) {
116 next = okra_parse_pchar(s, current);
117 if (next == -1)
118 next = (s[current] == '/' || s[current] == '?') ?
119 current+1 :
120 -1;
121
122 if (next == -1) break;
123 current = next;
124 }
125
126 ret = malloc(sizeof(OkraStringPiece));
127 ret->start = i;
128 ret->end = current;
129 return ret;
130 }
131
132 OkraStringPiece *
133 okra_parse_query(const char *s, int i)
134 {
135 return okra_parse_fragment(s, i);
136 }
137
138 int
139 okra_parse_segment_nz_nc(const char *s, int i)
140 {
141 char c;
142 int current = i, next;
143 for (;;) {
144 next = okra_parse_unreserved(s, current);
145 if (next == -1) next = okra_parse_sub_delim(s, current);
146 if (next == -1) next = s[current] == '@' ? current+1 : -1;
147 if (next == -1) next = okra_parse_pct_encoded(s, current);
148
149 if (next == -1) break;
150 current = next;
151 }
152 if (current == i) return -1;
153 return current;
154 }
155
156 int
157 okra_parse_segment_nz(const char *s, int i)
158 {
159 int current = i, next;
160 for (;;) {
161 next = okra_parse_pchar(s, current);
162
163 if (next == -1) break;
164 current = next;
165 }
166 if (current == i) return -1;
167 return current;
168 }
169
170 int
171 okra_parse_segment(const char *s, int i)
172 {
173 int current = i, next;
174 for (;;) {
175 next = okra_parse_pchar(s, current);
176
177 if (next == -1) break;
178 current = next;
179 }
180 return current;
181 }
182
183 OkraPathComponent *
184 okra_parse_path_empty(const char *s, int i)
185 {
186 OkraPathComponent *ret = NULL;
187 int next = okra_parse_pchar(s, i);
188 if (next != -1) return NULL;
189
190 ret = calloc(1, sizeof(OkraPathComponent));
191 ret->value = calloc(1, sizeof(OkraStringPiece));
192 ret->value->start = ret->value->end = i;
193 return ret;
194 }
195
196 OkraPathComponent *
197 okra_parse_path_abempty(const char *s, int i)
198 {
199 OkraPathComponent *ret = calloc(1, sizeof(OkraPathComponent));
200 int current = i, next;
201
202 ret->value = calloc(1, sizeof(OkraStringPiece));
203 ret->value->start = i;
204
205 for (;;) {
206 next = s[current] == '/' ? current+1 : -1;
207 // TODO convert okra_parse_segment to return OkraStringPiece,
208 // TODO insert them into ret->segments
209 if (next != -1) next = okra_parse_segment(s, next);
210
211 if (next == -1) break;
212 current = next;
213 }
214 ret->value->end = current;
215 return ret;
216 }
217
218 OkraPathComponent *
219 okra_parse_path_rootless(const char *s, int i)
220 {
221 OkraPathComponent *ret = NULL;
222 int current = i, next;
223 next = okra_parse_segment_nz(s, current);
224 if (next != -1) ret = okra_parse_path_abempty(s, next);
225 if (ret == NULL) return NULL;
226
227 // TODO pass the segment_nz to okra_parse_path_abempty...
228 ret->value->start = i;
229
230 return ret;
231 }
232
233 OkraPathComponent *
234 okra_parse_path_noscheme(const char *s, int i)
235 {
236 OkraPathComponent *ret = NULL;
237 int current = i, next;
238 next = okra_parse_segment_nz_nc(s, current);
239 if (next != -1) ret = okra_parse_path_abempty(s, next);
240 if (ret == NULL) return NULL;
241
242 ret->value->start = i;
243 return ret;
244 }
245
246 OkraPathComponent *
247 okra_parse_path_absolute(const char *s, int i)
248 {
249 OkraPathComponent *ret = NULL;
250 int current = i, next;
251
252 if (s[current] != '/') return NULL;
253 current++;
254
255 ret = okra_parse_path_rootless(s, current);
256 if (ret != NULL) {
257 ret->value->start = i;
258 return ret;
259 }
260
261 ret = calloc(1, sizeof(OkraPathComponent));
262 ret->value = calloc(1, sizeof(OkraStringPiece));
263 ret->value->start = i;
264 ret->value->end = i + 1;
265 return ret;
266 }
267
268 OkraPathComponent *
269 okra_parse_path(const char *s, int i)
270 {
271 OkraPathComponent *ret = NULL, *other;
272 ret = okra_parse_path_abempty(s, i);
273 if (ret == NULL) ret = okra_parse_path_absolute(s, i);
274 if (ret == NULL) ret = okra_parse_path_noscheme(s, i);
275 if (ret == NULL) ret = okra_parse_path_rootless(s, i);
276 if (ret == NULL) ret = okra_parse_path_empty(s, i);
277 return ret;
278 }
279
280 int
281 okra_parse_reg_name(const char *s, int i)
282 {
283 int current = i, next;
284 for (;;) {
285 next = okra_parse_unreserved(s, current);
286 if (next == -1) next = okra_parse_sub_delim(s, current);
287 if (next == -1) next = okra_parse_pct_encoded(s, current);
288 if (next == -1) break;
289 current = next;
290 }
291 return current;
292 }
293
294 int
295 okra_parse_dec_octet(const char *s, int i)
296 {
297 if (IS_DIGIT(s[i]) && !IS_DIGIT(s[i+1])) return i+1;
298 if (s[i] >= '1' && s[i] <= '9' && IS_DIGIT(s[i+1])) return i+2;
299 if (
300 (s[i] == '1' && IS_DIGIT(s[i+1]) && IS_DIGIT(s[i+2])) ||
301 (s[i] == '2' && RANGE('0', s[i+1], '4') && IS_DIGIT(s[i+2])) ||
302 (s[i] == '2' && s[i+1] == '5' && RANGE('0', s[i+2], '5'))
303 ) return i+3;
304 return -1;
305 }
306
307 int
308 okra_parse_ipv4_address(const char *s, int i)
309 {
310 int next = i;
311 next = okra_parse_dec_octet(s, next);
312 if (next != -1) next = s[next] == '.' ? next+1 : -1;
313 if (next != -1) next = okra_parse_dec_octet(s, next);
314 if (next != -1) next = s[next] == '.' ? next+1 : -1;
315 if (next != -1) next = okra_parse_dec_octet(s, next);
316 if (next != -1) next = s[next] == '.' ? next+1 : -1;
317 if (next != -1) next = okra_parse_dec_octet(s, next);
318 return next;
319 }
320
321 int
322 okra_parse_h16(const char *s, int i)
323 {
324 int matches = 0;
325 int current = i, next;
326 for (;;) {
327 next = okra_parse_hexdig(s, current);
328 if (next == -1) break;
329 current = next;
330 matches++;
331 if (matches == 4) break;
332 }
333 if (current == i) return -1;
334 return current;
335 }
336
337 int
338 okra_parse_ls32(const char *s, int i)
339 {
340 int next = okra_parse_h16(s, i);
341 if (next != -1) next = s[next] == ':' ? next+1 : -1;
342 if (next != -1) next = okra_parse_h16(s, next);
343 if (next != -1) return next;
344
345 return okra_parse_ipv4_address(s, i);
346 }
347
348 int
349 okra_parse_ipv6_address(const char *s, int i)
350 {
351 return -1; // TODO this rule is really ugly :(
352 }
353
354 int
355 okra_parse_ipvfuture(const char *s, int i)
356 {
357 if (s[i] != 'v') return -1;
358 i++;
359 if (okra_parse_hexdig(s, i) == -1) return -1;
360 i++;
361 if (s[i] != '.') return -1;
362 i++;
363
364 int current = i, next;
365 for (;;) {
366 next = okra_parse_unreserved(s, next);
367 if (next == -1) next = okra_parse_sub_delim(s, next);
368 if (next == -1) next = s[next] == ':' ? next+1 : -1;
369 if (next == -1) break;
370 current = next;
371 }
372 if (current == i) return -1;
373 return current;
374 }
375
376 int
377 okra_parse_ip_literal(const char *s, int i)
378 {
379 int next;
380 if (s[i] != '[') return -1;
381 i++;
382
383 next = okra_parse_ipv6_address(s, i);
384 if (next == -1) next = okra_parse_ipvfuture(s, i);
385 i = next;
386 if (s[i] != ']') return -1;
387 i++;
388 return i;
389 }
390
391 OkraStringPiece *
392 okra_parse_port(const char *s, int i)
393 {
394 OkraStringPiece *ret = NULL;
395 int current = i, next;
396 for (;;) {
397 next = okra_parse_digit(s, current);
398 if (next == -1) break;
399 current = next;
400 }
401 ret = malloc(sizeof(OkraStringPiece));
402 ret->start = i;
403 ret->end = current;
404 return ret;
405 }
406
407 OkraStringPiece *
408 okra_parse_host(const char *s, int i)
409 {
410 OkraStringPiece *ret = NULL;
411 int next = okra_parse_ip_literal(s, i);
412 if (next == -1) next = okra_parse_ipv4_address(s, i);
413 if (next == -1) next = okra_parse_reg_name(s, i);
414
415 if (next != -1) {
416 ret = malloc(sizeof(OkraStringPiece));
417 ret->start = i;
418 ret->end = next;
419 }
420 return ret;
421 }
422
423 OkraStringPiece *
424 okra_parse_userinfo(const char *s, int i)
425 {
426 OkraStringPiece *ret = NULL;
427 int current = i, next;
428 for (;;) {
429 next = okra_parse_unreserved(s, current);
430 if (next == -1) next = okra_parse_pct_encoded(s, current);
431 if (next == -1) next = okra_parse_sub_delim(s, current);
432 if (next == -1) next = s[current] == ':' ? current+1 : -1;
433 if (next == -1) break;
434 current = next;
435 }
436 if (current == -1) return NULL;
437
438 ret = malloc(sizeof(OkraStringPiece));
439 ret->start = i;
440 ret->end = current;
441 return ret;
442 }
443
444 OkraAuthorityComponent *
445 okra_parse_authority(const char *s, int i)
446 {
447 int i0 = i, next;
448 OkraAuthorityComponent *ret = NULL;
449 OkraStringPiece *userinfo = NULL;
450 OkraStringPiece *host = NULL;
451 OkraStringPiece *port = NULL;
452 OkraStringPiece *value = NULL;
453
454 // TODO clean this logic up...
455 userinfo = okra_parse_userinfo(s, i);
456 if (userinfo != NULL) {
457 next = userinfo->end;
458 next = s[next] == '@' ? next+1 : -1;
459 if (next != -1) i = next;
460 else {
461 free(userinfo);
462 userinfo = NULL;
463 }
464 }
465
466 host = okra_parse_host(s, i);
467 if (host == NULL) {
468 if (userinfo != NULL) free(userinfo);
469 return NULL;
470 }
471 i = host->end;
472
473 if (s[i] == ':') {
474 next = i+1;
475 port = okra_parse_port(s, next);
476 if (port != NULL) i = port->end;
477 }
478
479 value = malloc(sizeof(OkraStringPiece));
480 value->start = i0;
481 value->end = i;
482
483 ret = malloc(sizeof(OkraAuthorityComponent));
484 ret->userinfo = userinfo;
485 ret->host = host;
486 ret->port = port;
487 ret->value = value;
488 return ret;
489 }
490
491 OkraStringPiece *
492 okra_parse_scheme(const char *s, int i)
493 {
494 OkraStringPiece *ret = NULL;
495 int current = i, next = okra_parse_alpha(s, current);
496 if (next == -1) return NULL;
497 current = next;
498
499 for (;;) {
500 next = okra_parse_alpha(s, current);
501 if (next == -1) next = okra_parse_digit(s, current);
502 if (next == -1) next = (s[current] == '+' || s[current] == '-' || s[current] == '.') ? current+1 : -1;
503 if (next == -1) break;
504 current = next;
505 }
506
507 ret = malloc(sizeof(OkraStringPiece));
508 ret->start = i;
509 ret->end = current;
510 return ret;
511 }
512
513 OkraRelativePart *
514 okra_parse_relative_part(const char *s, int i)
515 {
516 OkraRelativePart *ret = NULL;
517 OkraPathComponent *path = NULL;
518 OkraAuthorityComponent *authority = NULL;
519 int current = i, next;
520
521 /* "//" authority path-abempty */
522 next = (s[current] == '/' && s[current+1] == '/') ? current+2 : -1;
523 if (next != -1) {
524 authority = okra_parse_authority(s, next);
525 next = authority == NULL ? -1 : authority->value->end;
526 }
527 if (next != -1) path = okra_parse_path_abempty(s, next);
528 if (path != NULL) {
529 ret = malloc(sizeof(OkraRelativePart));
530 ret->authority = authority;
531 ret->path = path;
532 return ret;
533 } else if (authority != NULL) free(authority); /* clean up */
534
535 path = okra_parse_path_absolute(s, i);
536 if (path == NULL) path = okra_parse_path_noscheme(s, i);
537 if (path == NULL) path = okra_parse_path_empty(s, i);
538 if (path == NULL) return NULL;
539
540 ret = malloc(sizeof(OkraRelativePart));
541 ret->authority = authority;
542 ret->path = path;
543 assert(ret->path != NULL);
544 return ret;
545 }
546
547 #define SAFE_FREE(name) if (name != NULL) free(name);
548 void
549 okra_free_raw_uri(OkraRawUri *raw)
550 {
551 SAFE_FREE(raw->scheme);
552 if (raw->authority != NULL) {
553 SAFE_FREE(raw->authority->value);
554 SAFE_FREE(raw->authority->userinfo);
555 SAFE_FREE(raw->authority->host);
556 SAFE_FREE(raw->authority->port);
557 SAFE_FREE(raw->authority);
558 }
559 if (raw->path != NULL) {
560 SAFE_FREE(raw->path->value);
561 SAFE_FREE(raw->path);
562 // TODO list of segments
563 }
564 if (raw->query != NULL) SAFE_FREE(raw->query);
565 if (raw->fragment != NULL) SAFE_FREE(raw->fragment);
566 SAFE_FREE(raw->value);
567 free(raw);
568
569 }
570
571 OkraRawUri *
572 okra_parse_relative_ref(const char *s, int i)
573 {
574 int i0 = i;
575 OkraRawUri *ret = NULL;
576 OkraStringPiece *query = NULL;
577 OkraStringPiece *fragment = NULL;
578 OkraRelativePart *rel_part = NULL;
579
580 rel_part = okra_parse_relative_part(s, i);
581 if (rel_part == NULL) return NULL;
582 i = rel_part->path->value->end; /* end of path is always end of rel_path. */
583
584 int next = i;
585 next = s[next] == '?' ? next+1 : -1;
586 if (next != -1) {
587 query = okra_parse_query(s, next);
588 next = query == NULL ? -1 : query->end;
589 }
590 if (next != -1) i = next; // TODO clean this up.. yuck...
591 next = i;
592
593 next = s[next] == '#' ? next+1 : -1;
594 if (next != -1) {
595 fragment = okra_parse_fragment(s, next);
596 next = fragment == NULL ? -1 : fragment->end;
597 }
598 if (next != -1) i = next;
599
600 ret = calloc(1, sizeof(OkraRawUri));
601 ret->buffer = s;
602 ret->authority = rel_part->authority;
603 ret->path = rel_part->path;
604 free(rel_part);
605 ret->query = query;
606 ret->fragment = fragment;
607 ret->value = malloc(sizeof(OkraStringPiece));
608 ret->value->start = i0;
609 ret->value->end = i;
610 return ret;
611 }
612
613 OkraRelativePart *
614 okra_parse_hier_part(const char *s, int i)
615 {
616 OkraRelativePart *ret = NULL;
617 OkraPathComponent *path = NULL;
618 OkraAuthorityComponent *authority = NULL;
619 int current = i, next;
620
621 /* "//" authority path-abempty */
622 next = (s[current] == '/' && s[current+1] == '/') ? current+2 : -1;
623 if (next != -1) {
624 authority = okra_parse_authority(s, next);
625 next = authority == NULL ? -1 : authority->value->end;
626 }
627 if (next != -1) path = okra_parse_path_abempty(s, next);
628 if (path != NULL) {
629 ret = malloc(sizeof(OkraRelativePart));
630 ret->authority = authority;
631 ret->path = path;
632 return ret;
633 } else if (authority != NULL) free(authority); /* clean up */
634
635 path = okra_parse_path_absolute(s, i);
636 if (path == NULL) path = okra_parse_path_rootless(s, i);
637 if (path == NULL) path = okra_parse_path_empty(s, i);
638 if (path == NULL) return NULL;
639
640 ret = malloc(sizeof(OkraRelativePart));
641 ret->authority = authority;
642 ret->path = path;
643 assert(ret->path != NULL);
644 return ret;
645 }
646
647 OkraRawUri *
648 okra_parse_absolute_uri(const char *s, int i)
649 {
650 int i0 = i;
651 OkraRawUri *ret = NULL;
652 OkraRelativePart *rel_part = NULL;
653 OkraStringPiece *scheme = NULL;
654 OkraStringPiece *query = NULL;
655 OkraStringPiece *value = NULL;
656
657 scheme = okra_parse_scheme(s, i);
658 if (scheme == NULL) return NULL;
659 i = scheme->end;
660
661 if (s[i] != ':') {
662 free(scheme);
663 return NULL;
664 }
665 i++;
666
667 // TODO extract components from hier_part? ew...
668
669 rel_part = okra_parse_hier_part(s, i);
670 if (rel_part == NULL) {
671 free(scheme);
672 return NULL;
673 }
674 i = rel_part->path->value->end;
675
676 if (s[i] == '?') {
677 int next = i+1;
678 query = okra_parse_query(s, next);
679 if (query != NULL) i = query->end;
680 }
681
682 ret = calloc(1, sizeof(OkraRawUri));
683 ret->buffer = s;
684 ret->scheme = scheme;
685 ret->query = query;
686
687 value = malloc(sizeof(OkraStringPiece));
688 value->start = i0;
689 value->end = i;
690 ret->value = value;
691
692 assert(rel_part != NULL);
693 ret->authority = rel_part->authority;
694 ret->path = rel_part->path;
695 free(rel_part);
696
697 return ret;
698 }
699
700 OkraRawUri *
701 okra_parse_uri(const char *s, int i)
702 {
703 OkraRawUri *ret = NULL;
704 OkraStringPiece *fragment = NULL;
705 ret = okra_parse_absolute_uri(s, i);
706 if (ret == NULL) return NULL;
707 assert(ret->value != NULL);
708 i = ret->value->end;
709
710 if (s[i] == '#') {
711 int next = i+1;
712 fragment = okra_parse_fragment(s, next);
713 if (fragment != NULL) i = fragment->end;
714 }
715
716 // if (s[i] != '\0') return NULL;
717 ret->fragment = fragment;
718 ret->value->end = i;
719
720 return ret;
721 }
722
723 OkraRawUri *
724 okra_parse_uri_ref(const char *s, int i)
725 {
726 OkraRawUri *ret = NULL;
727
728 ret = okra_parse_uri(s, i);
729 if (ret != NULL && s[ret->value->end] != '\0') {
730 okra_free_raw_uri(ret);
731 ret = NULL;
732 }
733 if (ret != NULL) return ret;
734
735 ret = okra_parse_relative_ref(s, i);
736 if (ret != NULL)
737 if (s[ret->value->end] != '\0') {
738 okra_free_raw_uri(ret);
739 ret = NULL;
740 }
741
742 return ret;
743 }
744
745 char *
746 okra_stralloc(OkraRawUri *uri, OkraStringPiece *piece)
747 {
748 int length;
749 char *ret;
750
751 if (piece == NULL) return NULL;
752
753 length = piece->end - piece->start;
754 ret = malloc((length+1) * sizeof(char));
755 for (int i = 0; i < length; i++)
756 ret[i] = uri->buffer[piece->start + i];
757 ret[length] = '\0';
758 return ret;
759 }
760
761 OkraUri *
762 okra_parse(const char *s)
763 {
764 OkraRawUri *raw = okra_parse_uri_ref(s, 0);
765 OkraUri *ret;
766
767 if (raw == NULL) return NULL;
768
769 /* transfer raw data into freshly allocated buffers, free as we go */
770 ret = calloc(1, sizeof(OkraUri));
771 if (raw->scheme != NULL) ret->scheme = okra_stralloc(raw, raw->scheme);
772 if (raw->authority != NULL) {
773 ret->authority = okra_stralloc(raw, raw->authority->value);
774 ret->userinfo = okra_stralloc(raw, raw->authority->userinfo);
775 ret->host = okra_stralloc(raw, raw->authority->host);
776 ret->port = okra_stralloc(raw, raw->authority->port);
777 }
778 if (raw->path != NULL) ret->path = okra_stralloc(raw, raw->path->value);
779 if (raw->query != NULL) ret->query = okra_stralloc(raw, raw->query);
780 if (raw->fragment != NULL) ret->fragment = okra_stralloc(raw, raw->fragment);
781 okra_free_raw_uri(raw);
782
783 /* recompose the uri into ret->uri */
784 ret->uri = okra_recompose(ret);
785
786 return ret;
787 }
This webpage is intended to be an accessible preview of this repository. To get a fuller picture, clone it and use the git CLI.