2 5546fdd5 2022-12-23 op * Copyright (c) 2022 Omar Polo <op@omarpolo.com>
4 5546fdd5 2022-12-23 op * Permission to use, copy, modify, and distribute this software for any
5 5546fdd5 2022-12-23 op * purpose with or without fee is hereby granted, provided that the above
6 5546fdd5 2022-12-23 op * copyright notice and this permission notice appear in all copies.
8 5546fdd5 2022-12-23 op * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 5546fdd5 2022-12-23 op * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 5546fdd5 2022-12-23 op * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 5546fdd5 2022-12-23 op * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 5546fdd5 2022-12-23 op * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 5546fdd5 2022-12-23 op * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 5546fdd5 2022-12-23 op * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 5546fdd5 2022-12-23 op #include <ctype.h>
18 871b5bb7 2022-12-24 op #include <errno.h>
19 871b5bb7 2022-12-24 op #include <stddef.h>
20 5546fdd5 2022-12-23 op #include <stdint.h>
21 a2785a57 2022-12-26 op #include <stdio.h>
22 5546fdd5 2022-12-23 op #include <stdlib.h>
23 5546fdd5 2022-12-23 op #include <string.h>
25 5546fdd5 2022-12-23 op #include "iri.h"
27 5546fdd5 2022-12-23 op /* TODO: URI -> IRI. accept IRI but emit always URI */
29 5546fdd5 2022-12-23 op static inline int
30 5546fdd5 2022-12-23 op cpstr(const char *start, const char *till, char *buf, size_t len)
32 5546fdd5 2022-12-23 op size_t slen = till - start;
34 5546fdd5 2022-12-23 op if (slen + 1 >= len)
36 5546fdd5 2022-12-23 op memcpy(buf, start, slen);
37 5546fdd5 2022-12-23 op buf[slen] = '\0';
41 5546fdd5 2022-12-23 op static inline int
42 5546fdd5 2022-12-23 op unreserved(int c)
44 5546fdd5 2022-12-23 op return (isalnum((unsigned char)c) ||
51 5546fdd5 2022-12-23 op static inline int
52 5546fdd5 2022-12-23 op pctenc(const char *s)
54 5546fdd5 2022-12-23 op const char *t = s;
56 5546fdd5 2022-12-23 op return (t[0] == '%' &&
57 5546fdd5 2022-12-23 op isxdigit((unsigned char)t[1]) &&
58 5546fdd5 2022-12-23 op isxdigit((unsigned char)t[2]));
61 5546fdd5 2022-12-23 op static inline int
62 5546fdd5 2022-12-23 op sub_delims(int c)
64 5546fdd5 2022-12-23 op return (c == '!' || c == '$' || c == '&' || c == '\'' ||
65 5546fdd5 2022-12-23 op c == '(' || c == ')' || c == '*' || c == '+' || c == ',' ||
66 5546fdd5 2022-12-23 op c == ';' || c == '=');
69 5546fdd5 2022-12-23 op static inline const char *
70 5546fdd5 2022-12-23 op advance_pchar(const char *s)
72 5546fdd5 2022-12-23 op if (unreserved(*s) || sub_delims(*s) || *s == ':' || *s == '@')
73 5546fdd5 2022-12-23 op return (s + 1);
74 5546fdd5 2022-12-23 op if (pctenc(s))
75 5546fdd5 2022-12-23 op return (s + 3);
76 5546fdd5 2022-12-23 op return (NULL);
79 5546fdd5 2022-12-23 op static inline const char *
80 5546fdd5 2022-12-23 op advance_segment(const char *s)
82 5546fdd5 2022-12-23 op const char *t = s;
84 5546fdd5 2022-12-23 op while ((t = advance_pchar(s)) != NULL)
89 5546fdd5 2022-12-23 op static inline const char *
90 5546fdd5 2022-12-23 op advance_segment_nz(const char *s)
92 5546fdd5 2022-12-23 op const char *t;
94 5546fdd5 2022-12-23 op if ((t = advance_pchar(s)) == NULL)
95 5546fdd5 2022-12-23 op return (NULL);
96 5546fdd5 2022-12-23 op return (advance_segment(t));
99 5546fdd5 2022-12-23 op static inline const char *
100 5546fdd5 2022-12-23 op advance_segment_nz_nc(const char *s)
102 5546fdd5 2022-12-23 op const char *t = s;
105 5546fdd5 2022-12-23 op if (unreserved(*t) || sub_delims(*t) || *t == '@')
107 5546fdd5 2022-12-23 op else if (pctenc(t))
113 5546fdd5 2022-12-23 op return (t != s ? t : NULL);
116 5546fdd5 2022-12-23 op static const char *
117 5546fdd5 2022-12-23 op parse_scheme(const char *s, struct iri *iri)
119 5546fdd5 2022-12-23 op const char *t = s;
121 5546fdd5 2022-12-23 op if (!isalpha((unsigned char)*t))
122 5546fdd5 2022-12-23 op return (NULL);
124 5546fdd5 2022-12-23 op while (isalnum((unsigned char)*t) ||
130 5546fdd5 2022-12-23 op if (cpstr(s, t, iri->iri_scheme, sizeof(iri->iri_scheme)) == -1)
131 5546fdd5 2022-12-23 op return (NULL);
133 5546fdd5 2022-12-23 op iri->iri_flags |= IH_SCHEME;
137 5546fdd5 2022-12-23 op /* userinfo is always optional */
138 5546fdd5 2022-12-23 op static const char *
139 5546fdd5 2022-12-23 op parse_uinfo(const char *s, struct iri *iri)
141 5546fdd5 2022-12-23 op const char *t = s;
144 5546fdd5 2022-12-23 op if (unreserved(*t) || sub_delims(*t) || *t == ':')
146 5546fdd5 2022-12-23 op else if (pctenc(t))
152 5546fdd5 2022-12-23 op if (*t != '@')
155 5546fdd5 2022-12-23 op if (cpstr(s, t, iri->iri_uinfo, sizeof(iri->iri_uinfo)) == -1)
156 5546fdd5 2022-12-23 op return (NULL);
157 5546fdd5 2022-12-23 op iri->iri_flags |= IH_UINFO;
158 5546fdd5 2022-12-23 op return (t + 1);
161 5546fdd5 2022-12-23 op static const char *
162 5546fdd5 2022-12-23 op parse_host(const char *s, struct iri *iri)
164 5546fdd5 2022-12-23 op const char *t = s;
167 5546fdd5 2022-12-23 op * cheating a bit by relaxing and merging the rule for
168 5546fdd5 2022-12-23 op * IPv6address and IPvFuture and by merging IPv4address and
172 5546fdd5 2022-12-23 op if (*t == '[') {
173 5546fdd5 2022-12-23 op while (*t && *t != ']')
175 5546fdd5 2022-12-23 op if (*t == '\0')
176 5546fdd5 2022-12-23 op return (NULL);
178 5546fdd5 2022-12-23 op if (cpstr(s, t, iri->iri_host, sizeof(iri->iri_host)) == -1)
179 5546fdd5 2022-12-23 op return (NULL);
180 5546fdd5 2022-12-23 op iri->iri_flags |= IH_HOST;
185 5546fdd5 2022-12-23 op if (unreserved(*t) || sub_delims(*t))
187 5546fdd5 2022-12-23 op else if (pctenc(t))
193 5546fdd5 2022-12-23 op if (cpstr(s, t, iri->iri_host, sizeof(iri->iri_host)) == -1)
194 5546fdd5 2022-12-23 op return (NULL);
195 5546fdd5 2022-12-23 op iri->iri_flags |= IH_HOST;
199 5546fdd5 2022-12-23 op static const char *
200 5546fdd5 2022-12-23 op parse_port(const char *s, struct iri *iri)
202 5546fdd5 2022-12-23 op const char *t = s;
203 5546fdd5 2022-12-23 op const char *errstr;
205 5546fdd5 2022-12-23 op while (isdigit((unsigned char)*t))
207 5546fdd5 2022-12-23 op if (cpstr(s, t, iri->iri_portstr, sizeof(iri->iri_portstr)) == -1)
208 5546fdd5 2022-12-23 op return (NULL);
209 5546fdd5 2022-12-23 op iri->iri_port = strtonum(iri->iri_portstr, 1, UINT16_MAX, &errstr);
211 5546fdd5 2022-12-23 op return (NULL);
212 5546fdd5 2022-12-23 op iri->iri_flags |= IH_PORT;
216 5546fdd5 2022-12-23 op static const char *
217 5546fdd5 2022-12-23 op parse_authority(const char *s, struct iri *iri)
219 5546fdd5 2022-12-23 op const char *t;
221 5546fdd5 2022-12-23 op if ((t = parse_uinfo(s, iri)) == NULL)
222 5546fdd5 2022-12-23 op return (NULL);
224 5546fdd5 2022-12-23 op if ((t = parse_host(t, iri)) == NULL)
225 5546fdd5 2022-12-23 op return (NULL);
227 5546fdd5 2022-12-23 op if (*t == ':')
228 870edfb9 2022-12-25 op return (parse_port(t + 1, iri));
233 5546fdd5 2022-12-23 op static const char *
234 5546fdd5 2022-12-23 op parse_path_abempty(const char *s, struct iri *iri)
236 5546fdd5 2022-12-23 op const char *t = s;
238 5546fdd5 2022-12-23 op while (*t == '/')
239 5546fdd5 2022-12-23 op t = advance_segment(t + 1);
241 5546fdd5 2022-12-23 op if (cpstr(s, t, iri->iri_path, sizeof(iri->iri_path)) == -1)
242 5546fdd5 2022-12-23 op return (NULL);
243 5546fdd5 2022-12-23 op iri->iri_flags |= IH_PATH;
247 5546fdd5 2022-12-23 op static const char *
248 5546fdd5 2022-12-23 op parse_path_absolute(const char *s, struct iri *iri)
250 5546fdd5 2022-12-23 op const char *t;
252 5546fdd5 2022-12-23 op if (*s != '/')
253 5546fdd5 2022-12-23 op return (NULL);
255 5546fdd5 2022-12-23 op if ((t = advance_segment_nz(s + 1)) == NULL)
256 5546fdd5 2022-12-23 op return (s + 1);
258 5546fdd5 2022-12-23 op while (*t == '/')
259 5546fdd5 2022-12-23 op t = advance_segment(t + 1);
261 5546fdd5 2022-12-23 op if (cpstr(s, t, iri->iri_path, sizeof(iri->iri_path)) == -1)
262 5546fdd5 2022-12-23 op return (NULL);
263 5546fdd5 2022-12-23 op iri->iri_flags |= IH_PATH;
267 5546fdd5 2022-12-23 op static const char *
268 5546fdd5 2022-12-23 op parse_path_rootless(const char *s, struct iri *iri)
270 5546fdd5 2022-12-23 op const char *t;
272 5546fdd5 2022-12-23 op if ((t = advance_segment_nz(s)) == NULL)
273 5546fdd5 2022-12-23 op return (NULL);
275 5546fdd5 2022-12-23 op while (*t == '/')
276 5546fdd5 2022-12-23 op t = advance_segment(t + 1);
278 5546fdd5 2022-12-23 op if (cpstr(s, t, iri->iri_path, sizeof(iri->iri_path)) == -1)
279 5546fdd5 2022-12-23 op return (NULL);
280 5546fdd5 2022-12-23 op iri->iri_flags |= IH_PATH;
284 5546fdd5 2022-12-23 op static const char *
285 5546fdd5 2022-12-23 op parse_path_noscheme(const char *s, struct iri *iri)
287 5546fdd5 2022-12-23 op const char *t;
289 5546fdd5 2022-12-23 op if ((t = advance_segment_nz_nc(s)) == NULL)
290 5546fdd5 2022-12-23 op return (NULL);
292 5546fdd5 2022-12-23 op while (*t == '/')
293 5546fdd5 2022-12-23 op t = advance_segment(t + 1);
295 5546fdd5 2022-12-23 op if (cpstr(s, t, iri->iri_path, sizeof(iri->iri_path)) == -1)
296 5546fdd5 2022-12-23 op return (NULL);
297 5546fdd5 2022-12-23 op iri->iri_flags |= IH_PATH;
301 5546fdd5 2022-12-23 op static const char *
302 5546fdd5 2022-12-23 op parse_path_empty(const char *s, struct iri *iri)
304 5546fdd5 2022-12-23 op iri->iri_path[0] = '\0';
305 5546fdd5 2022-12-23 op iri->iri_flags |= IH_PATH;
309 5546fdd5 2022-12-23 op static const char *
310 5546fdd5 2022-12-23 op parse_hier(const char *s, struct iri *iri)
312 5546fdd5 2022-12-23 op const char *t;
314 5546fdd5 2022-12-23 op if (!strncmp(s, "//", 2)) {
315 5546fdd5 2022-12-23 op if ((t = parse_authority(s + 2, iri)) == NULL)
316 5546fdd5 2022-12-23 op return (NULL);
317 5546fdd5 2022-12-23 op return (parse_path_abempty(t, iri));
320 5546fdd5 2022-12-23 op if ((t = parse_path_absolute(s, iri)) != NULL)
323 5546fdd5 2022-12-23 op if ((t = parse_path_rootless(s, iri)) != NULL)
326 5546fdd5 2022-12-23 op return (parse_path_empty(s, iri));
329 5546fdd5 2022-12-23 op static const char *
330 5546fdd5 2022-12-23 op parse_relative(const char *s, struct iri *iri)
332 5546fdd5 2022-12-23 op const char *t = s;
334 5546fdd5 2022-12-23 op if (!strncmp(s, "//", 2)) {
335 5546fdd5 2022-12-23 op if ((t = parse_authority(s + 2, iri)) == NULL)
336 5546fdd5 2022-12-23 op return (NULL);
337 5546fdd5 2022-12-23 op return (parse_path_abempty(t, iri));
340 5546fdd5 2022-12-23 op if ((t = parse_path_absolute(s, iri)) != NULL)
343 5546fdd5 2022-12-23 op if ((t = parse_path_noscheme(s, iri)) != NULL)
346 5546fdd5 2022-12-23 op return (parse_path_empty(s, iri));
349 5546fdd5 2022-12-23 op static const char *
350 5546fdd5 2022-12-23 op parse_query(const char *s, struct iri *iri)
352 5546fdd5 2022-12-23 op const char *n, *t = s;
355 5546fdd5 2022-12-23 op if ((n = advance_pchar(t)) != NULL)
357 5546fdd5 2022-12-23 op else if (*t == '/' || *t == '?')
363 5546fdd5 2022-12-23 op if (cpstr(s, t, iri->iri_query, sizeof(iri->iri_query)) == -1)
364 5546fdd5 2022-12-23 op return (NULL);
365 5546fdd5 2022-12-23 op iri->iri_flags |= IH_QUERY;
369 a165601e 2022-12-25 op static const char *
370 a165601e 2022-12-25 op parse_fragment(const char *s, struct iri *iri)
372 a165601e 2022-12-25 op const char *n, *t = s;
375 a165601e 2022-12-25 op if ((n = advance_pchar(t)) != NULL)
377 a165601e 2022-12-25 op else if (*t == '/' || *t == '?')
383 a165601e 2022-12-25 op if (cpstr(s, t, iri->iri_fragment, sizeof(iri->iri_fragment)) == -1)
384 a165601e 2022-12-25 op return (NULL);
385 a165601e 2022-12-25 op iri->iri_flags |= IH_FRAGMENT;
390 5546fdd5 2022-12-23 op parse_uri(const char *s, struct iri *iri)
392 5546fdd5 2022-12-23 op if ((s = parse_scheme(s, iri)) == NULL)
395 5546fdd5 2022-12-23 op if (*s != ':')
398 5546fdd5 2022-12-23 op if ((s = parse_hier(s + 1, iri)) == NULL)
401 5546fdd5 2022-12-23 op if (*s == '?' && (s = parse_query(s + 1, iri)) == NULL)
404 a165601e 2022-12-25 op if (*s == '#' && (s = parse_fragment(s + 1, iri)) == NULL)
407 a165601e 2022-12-25 op if (*s == '\0')
414 5546fdd5 2022-12-23 op parse_relative_ref(const char *s, struct iri *iri)
416 5546fdd5 2022-12-23 op if ((s = parse_relative(s, iri)) == NULL)
419 5546fdd5 2022-12-23 op if (*s == '?' && (s = parse_query(s + 1, iri)) == NULL)
422 a165601e 2022-12-25 op if (*s == '#' && (s = parse_fragment(s + 1, iri)) == NULL)
425 a165601e 2022-12-25 op if (*s == '\0')
432 5546fdd5 2022-12-23 op parse(const char *s, struct iri *iri)
434 5546fdd5 2022-12-23 op iri->iri_flags = 0;
436 5546fdd5 2022-12-23 op if (s == NULL)
439 5546fdd5 2022-12-23 op if (parse_uri(s, iri) == -1) {
440 5546fdd5 2022-12-23 op iri->iri_flags = 0;
441 5546fdd5 2022-12-23 op if (parse_relative_ref(s, iri) == -1)
448 51762770 2022-12-24 op static inline void
449 51762770 2022-12-24 op lowerify(char *s)
451 51762770 2022-12-24 op for (; *s; ++s)
452 51762770 2022-12-24 op *s = tolower((unsigned char)*s);
456 5546fdd5 2022-12-23 op cpfields(struct iri *dest, const struct iri *src, int flags)
458 5546fdd5 2022-12-23 op if (flags & IH_SCHEME) {
459 5546fdd5 2022-12-23 op dest->iri_flags |= IH_SCHEME;
460 5546fdd5 2022-12-23 op if (src->iri_flags & IH_SCHEME)
461 5546fdd5 2022-12-23 op memcpy(dest->iri_scheme, src->iri_scheme,
462 5546fdd5 2022-12-23 op sizeof(dest->iri_scheme));
463 51762770 2022-12-24 op lowerify(dest->iri_scheme);
465 5546fdd5 2022-12-23 op if (flags & IH_UINFO) {
466 997b9cd0 2022-12-24 op if (src->iri_flags & IH_UINFO) {
467 5546fdd5 2022-12-23 op memcpy(dest->iri_uinfo, src->iri_uinfo,
468 5546fdd5 2022-12-23 op sizeof(dest->iri_uinfo));
469 997b9cd0 2022-12-24 op dest->iri_flags |= IH_UINFO;
472 5546fdd5 2022-12-23 op if (flags & IH_HOST) {
473 5546fdd5 2022-12-23 op dest->iri_flags |= IH_HOST;
474 5546fdd5 2022-12-23 op if (src->iri_flags & IH_HOST)
475 5546fdd5 2022-12-23 op memcpy(dest->iri_host, src->iri_host,
476 5546fdd5 2022-12-23 op sizeof(dest->iri_host));
477 51762770 2022-12-24 op lowerify(dest->iri_host);
479 5546fdd5 2022-12-23 op if (flags & IH_PORT) {
480 997b9cd0 2022-12-24 op if (src->iri_flags & IH_PORT) {
481 5546fdd5 2022-12-23 op dest->iri_port = src->iri_port;
482 997b9cd0 2022-12-24 op dest->iri_flags |= IH_PORT;
485 5546fdd5 2022-12-23 op if (flags & IH_PATH) {
486 5546fdd5 2022-12-23 op dest->iri_flags |= IH_PATH;
487 5546fdd5 2022-12-23 op if (src->iri_flags & IH_PATH)
488 5546fdd5 2022-12-23 op memcpy(dest->iri_path, src->iri_path,
489 5546fdd5 2022-12-23 op sizeof(dest->iri_path));
491 5546fdd5 2022-12-23 op if (flags & IH_QUERY) {
492 997b9cd0 2022-12-24 op if (src->iri_flags & IH_QUERY) {
493 997b9cd0 2022-12-24 op dest->iri_flags |= IH_QUERY;
494 5546fdd5 2022-12-23 op memcpy(dest->iri_query, src->iri_query,
495 5546fdd5 2022-12-23 op sizeof(dest->iri_query));
498 a165601e 2022-12-25 op if (flags & IH_FRAGMENT) {
499 a165601e 2022-12-25 op if (src->iri_flags & IH_FRAGMENT) {
500 a165601e 2022-12-25 op dest->iri_flags |= IH_FRAGMENT;
501 a165601e 2022-12-25 op memcpy(dest->iri_fragment, src->iri_fragment,
502 a165601e 2022-12-25 op sizeof(dest->iri_fragment));
507 871b5bb7 2022-12-24 op static inline int
508 8b2b06b5 2022-12-25 op remove_dot_segments(struct iri *i)
510 8b2b06b5 2022-12-25 op char *p, *q, *buf;
511 871b5bb7 2022-12-24 op ptrdiff_t bufsize;
513 8b2b06b5 2022-12-25 op buf = p = q = i->iri_path;
514 8b2b06b5 2022-12-25 op bufsize = sizeof(i->iri_path);
515 871b5bb7 2022-12-24 op while (*p && (q - buf < bufsize)) {
516 8b2b06b5 2022-12-25 op if (p[0] == '/' && p[1] == '.' &&
517 8b2b06b5 2022-12-25 op (p[2] == '/' || p[2] == '\0')) {
519 8b2b06b5 2022-12-25 op if (*p != '/')
521 8b2b06b5 2022-12-25 op } else if (p[0] == '/' && p[1] == '.' && p[2] == '.' &&
522 871b5bb7 2022-12-24 op (p[3] == '/' || p[3] == '\0')) {
524 8b2b06b5 2022-12-25 op while (q > buf && *--q != '/')
526 8b2b06b5 2022-12-25 op if (*p != '/' && (q > buf && q[-1] != '/'))
531 8b2b06b5 2022-12-25 op if ((*p == '\0') && (q - buf < bufsize)) {
536 871b5bb7 2022-12-24 op errno = ENAMETOOLONG;
540 871b5bb7 2022-12-24 op static inline int
541 871b5bb7 2022-12-24 op mergepath(struct iri *i, struct iri *base, struct iri *r)
543 871b5bb7 2022-12-24 op const char *bpath, *rpath, *s;
545 871b5bb7 2022-12-24 op bpath = (base->iri_flags & IH_PATH) ? base->iri_path : "/";
546 871b5bb7 2022-12-24 op rpath = (r->iri_flags & IH_PATH) ? r->iri_path : "/";
548 871b5bb7 2022-12-24 op i->iri_flags |= IH_PATH;
549 871b5bb7 2022-12-24 op i->iri_path[0] = '\0';
551 871b5bb7 2022-12-24 op if ((base->iri_flags & IH_AUTHORITY) &&
552 871b5bb7 2022-12-24 op (*bpath == '\0' || !strcmp(bpath, "/"))) {
553 871b5bb7 2022-12-24 op if (*rpath == '/')
555 871b5bb7 2022-12-24 op strlcpy(i->iri_path, "/", sizeof(i->iri_path));
556 871b5bb7 2022-12-24 op strlcat(i->iri_path, rpath, sizeof(i->iri_path));
560 871b5bb7 2022-12-24 op if ((s = strrchr(bpath, '/')) != NULL) {
561 871b5bb7 2022-12-24 op cpstr(bpath, s + 1, i->iri_path, sizeof(i->iri_path));
562 871b5bb7 2022-12-24 op if (*rpath == '/')
565 871b5bb7 2022-12-24 op if (strlcat(i->iri_path, rpath, sizeof(i->iri_path)) >=
566 871b5bb7 2022-12-24 op sizeof(i->iri_path)) {
567 871b5bb7 2022-12-24 op errno = ENAMETOOLONG;
575 5546fdd5 2022-12-23 op iri_parse(const char *base, const char *str, struct iri *iri)
577 5546fdd5 2022-12-23 op static struct iri ibase, iparsed;
579 5546fdd5 2022-12-23 op memset(iri, 0, sizeof(*iri));
581 5546fdd5 2022-12-23 op if (base == NULL) {
582 5546fdd5 2022-12-23 op ibase.iri_flags = 0;
583 f5bc8482 2022-12-24 op if (parse_uri(str, &iparsed) == -1) {
584 f5bc8482 2022-12-24 op errno = EINVAL;
588 f5bc8482 2022-12-24 op if (parse_uri(base, &ibase) == -1 ||
589 f5bc8482 2022-12-24 op parse(str, &iparsed) == -1) {
590 f5bc8482 2022-12-24 op errno = EINVAL;
595 a165601e 2022-12-25 op cpfields(iri, &iparsed, IH_FRAGMENT);
597 5546fdd5 2022-12-23 op if (iparsed.iri_flags & IH_SCHEME) {
598 5546fdd5 2022-12-23 op cpfields(iri, &iparsed, iparsed.iri_flags);
599 5546fdd5 2022-12-23 op remove_dot_segments(iri);
603 5546fdd5 2022-12-23 op cpfields(iri, &ibase, IH_SCHEME);
605 5546fdd5 2022-12-23 op if (iparsed.iri_flags & IH_HOST) {
606 5546fdd5 2022-12-23 op cpfields(iri, &iparsed, IH_AUTHORITY|IH_PATH|IH_QUERY);
607 5546fdd5 2022-12-23 op remove_dot_segments(iri);
611 5546fdd5 2022-12-23 op cpfields(iri, &ibase, IH_AUTHORITY);
613 5546fdd5 2022-12-23 op if ((iparsed.iri_flags & IH_PATH) && *iparsed.iri_path == '\0') {
614 5546fdd5 2022-12-23 op cpfields(iri, &ibase, IH_PATH);
615 5546fdd5 2022-12-23 op if (iparsed.iri_flags & IH_QUERY)
616 5546fdd5 2022-12-23 op cpfields(iri, &iparsed, IH_QUERY);
618 5546fdd5 2022-12-23 op cpfields(iri, &ibase, IH_QUERY);
622 5546fdd5 2022-12-23 op cpfields(iri, &iparsed, IH_QUERY);
623 5cb6cd4d 2022-12-24 op if ((iparsed.iri_flags & IH_PATH) && *iparsed.iri_path == '/')
624 5546fdd5 2022-12-23 op cpfields(iri, &iparsed, IH_PATH);
626 5546fdd5 2022-12-23 op if (!(ibase.iri_flags & IH_PATH))
627 5546fdd5 2022-12-23 op ibase.iri_path[0] = '\0';
628 5546fdd5 2022-12-23 op if (!(iparsed.iri_flags & IH_PATH))
629 5546fdd5 2022-12-23 op iparsed.iri_path[0] = '\0';
630 f5bc8482 2022-12-24 op if (mergepath(iri, &ibase, &iparsed) == -1)
633 f5bc8482 2022-12-24 op if (remove_dot_segments(iri) == -1)
639 d59fad58 2022-12-24 op iri_unparse(const struct iri *i, char *buf, size_t buflen)
641 d59fad58 2022-12-24 op if (buflen == 0)
644 d59fad58 2022-12-24 op /* TODO: should %enc octets if needed */
646 d59fad58 2022-12-24 op buf[0] = '\0';
648 d59fad58 2022-12-24 op if (i->iri_flags & IH_SCHEME) {
649 d59fad58 2022-12-24 op if (strlcat(buf, i->iri_scheme, buflen) >= buflen ||
650 d59fad58 2022-12-24 op strlcat(buf, ":", buflen) >= buflen)
654 d59fad58 2022-12-24 op if (i->iri_flags & IH_AUTHORITY) {
655 d59fad58 2022-12-24 op if (strlcat(buf, "//", buflen) >= buflen)
659 d59fad58 2022-12-24 op if (i->iri_flags & IH_UINFO) {
660 d59fad58 2022-12-24 op if (strlcat(buf, i->iri_uinfo, buflen) >= buflen ||
661 d59fad58 2022-12-24 op strlcat(buf, "@", buflen) >= buflen)
664 d59fad58 2022-12-24 op if (i->iri_flags & IH_HOST) {
665 d59fad58 2022-12-24 op if (strlcat(buf, i->iri_host, buflen) >= buflen)
668 d59fad58 2022-12-24 op if (i->iri_flags & IH_PORT) {
669 d59fad58 2022-12-24 op if (strlcat(buf, ":", buflen) >= buflen ||
670 d59fad58 2022-12-24 op strlcat(buf, i->iri_portstr, buflen) >= buflen)
674 d59fad58 2022-12-24 op if (i->iri_flags & IH_PATH) {
675 a655e85a 2022-12-24 op if (i->iri_flags & IH_AUTHORITY &&
676 d59fad58 2022-12-24 op i->iri_path[0] != '/' &&
677 d59fad58 2022-12-24 op strlcat(buf, "/", buflen) >= buflen)
679 d59fad58 2022-12-24 op if (strlcat(buf, i->iri_path, buflen) >= buflen)
683 d59fad58 2022-12-24 op if (i->iri_flags & IH_QUERY) {
684 d59fad58 2022-12-24 op if (strlcat(buf, "?", buflen) >= buflen ||
685 d59fad58 2022-12-24 op strlcat(buf, i->iri_query, buflen) >= buflen)
689 a165601e 2022-12-25 op if (i->iri_flags & IH_FRAGMENT) {
690 a165601e 2022-12-25 op if (strlcat(buf, "#", buflen) >= buflen ||
691 a165601e 2022-12-25 op strlcat(buf, i->iri_fragment, buflen) >= buflen)
698 d59fad58 2022-12-24 op errno = ENOBUFS;
703 5546fdd5 2022-12-23 op iri_human(const struct iri *iri, char *buf, size_t buflen)
705 5546fdd5 2022-12-23 op memset(buf, 0, buflen);
710 a2785a57 2022-12-26 op iri_setquery(struct iri *iri, const char *p)
712 a2785a57 2022-12-26 op ptrdiff_t bufsize;
714 a2785a57 2022-12-26 op char *buf, *q;
716 a2785a57 2022-12-26 op buf = q = iri->iri_query;
717 a2785a57 2022-12-26 op bufsize = sizeof(iri->iri_query);
718 a2785a57 2022-12-26 op while (*p && (q - buf < bufsize)) {
719 a2785a57 2022-12-26 op if (unreserved(*p) || sub_delims(*p) || *p == ':' || *p == '@' ||
720 a2785a57 2022-12-26 op *p == '/' || *p == '?')
723 a2785a57 2022-12-26 op if (q - buf >= bufsize - 4)
725 a2785a57 2022-12-26 op r = snprintf(q, 4, "%%%02X", (int)*p);
726 a2785a57 2022-12-26 op if (r < 0 || r > 4)
731 a2785a57 2022-12-26 op if ((*p == '\0') && (q - buf < bufsize)) {
732 a2785a57 2022-12-26 op iri->iri_flags |= IH_QUERY;
738 a2785a57 2022-12-26 op errno = ENOBUFS;