Objectively 1.0.0
Ultra-lightweight object oriented framework for GNU C.
URL.c
Go to the documentation of this file.
1/*
2 * Objectively: Ultra-lightweight object oriented framework for GNU C.
3 * Copyright (C) 2014 Jay Dolan <jay@jaydolan.com>
4 *
5 * This software is provided 'as-is', without any express or implied
6 * warranty. In no event will the authors be held liable for any damages
7 * arising from the use of this software.
8 *
9 * Permission is granted to anyone to use this software for any purpose,
10 * including commercial applications, and to alter it and redistribute it
11 * freely, subject to the following restrictions:
12 *
13 * 1. The origin of this software must not be misrepresented; you must not
14 * claim that you wrote the original software. If you use this software
15 * in a product, an acknowledgment in the product documentation would be
16 * appreciated but is not required.
17 *
18 * 2. Altered source versions must be plainly marked as such, and must not be
19 * misrepresented as being the original software.
20 *
21 * 3. This notice may not be removed or altered from any source distribution.
22 */
23
24#include <assert.h>
25#include <stdlib.h>
26
27#include "MutableString.h"
28#include "Regexp.h"
29#include "URL.h"
30
31#define _Class _URL
32
33#pragma mark - Object
34
38static Object *copy(const Object *self) {
39
40 const URL *this = (URL *) self;
41
42 return (Object *) $(alloc(URL), initWithString, this->urlString);
43}
44
48static void dealloc(Object *self) {
49
50 URL *this = (URL *) self;
51
52 release(this->fragment);
53 release(this->host);
54 release(this->path);
55 release(this->query);
56 release(this->scheme);
57 release(this->urlString);
58
59 super(Object, self, dealloc);
60}
61
65static String *description(const Object *self) {
66
67 const URL *this = (URL *) self;
68
69 return $((Object *) this->urlString, description);
70}
71
75static int hash(const Object *self) {
76
77 const URL *this = (URL *) self;
78
79 return $((Object *) this->urlString, hash);
80}
81
85static _Bool isEqual(const Object *self, const Object *other) {
86
87 if (super(Object, self, isEqual, other)) {
88 return true;
89 }
90
91 if (other && self->clazz == other->clazz) {
92
93 const URL *this = (URL *) self;
94 const URL *that = (URL *) other;
95
96 return $((Object *) this->urlString, isEqual, (Object *) that->urlString);
97 }
98
99 return false;
100}
101
102#pragma mark - URL
103
108static URL *baseURL(const URL *self) {
109
110 MutableString *string = $(alloc(MutableString), init);
111
112 $(string, appendString, self->scheme);
113 $(string, appendFormat, "://");
114
115 if (self->host) {
116 $(string, appendString, self->host);
117 }
118
119 if (self->port) {
120 $(string, appendFormat, ":%u", self->port);
121 }
122
123 URL *baseURL = $(alloc(URL), initWithString, (String *) string);
124
125 release(string);
126
127 return baseURL;
128}
129
130static Regexp *_re;
131
136static URL *initWithCharacters(URL *self, const char *chars) {
137
138 assert(chars);
139
140 self = (URL *) super(Object, self, init);
141 if (self) {
142
143 Range *ranges;
144 if ($(_re, matchesCharacters, chars, 0, &ranges)) {
145
146 self->urlString = $(alloc(String), initWithCharacters, chars);
147
148 Range *scheme = &ranges[1];
149 Range *host = &ranges[2];
150 Range *port = &ranges[3];
151 Range *path = &ranges[4];
152 Range *query = &ranges[5];
153 Range *fragment = &ranges[6];
154
155 self->scheme = $(self->urlString, substring, *scheme);
156
157 if (host->location > -1) {
158 self->host = $(self->urlString, substring, *host);
159
160 if (port->location > -1) {
161 const char *s = self->urlString->chars + port->location + 1;
162 self->port = strtoul(s, NULL, 10);
163 }
164 }
165
166 if (path->location > -1) {
167 self->path = $(self->urlString, substring, *path);
168 }
169
170 if (query->location > -1) {
171
172 query->location++;
173 query->length--;
174
175 self->query = $(self->urlString, substring, *query);
176 }
177
178 if (fragment->location > -1) {
179
180 fragment->location++;
181 fragment->length--;
182
183 self->fragment = $(self->urlString, substring, *fragment);
184 }
185
186 free(ranges);
187 } else {
188 self = release(self);
189 }
190 }
191
192 return self;
193}
194
199static URL *initWithString(URL *self, const String *string) {
200
201 assert(string);
202
203 return $(self, initWithCharacters, string->chars);
204}
205
210static Array *pathComponents(const URL *self) {
211
212 return $(self->path, componentsSeparatedByCharacters, "/");
213}
214
215#pragma mark - Class lifecycle
216
220static void initialize(Class *clazz) {
221
222 ((ObjectInterface *) clazz->interface)->copy = copy;
223 ((ObjectInterface *) clazz->interface)->dealloc = dealloc;
224 ((ObjectInterface *) clazz->interface)->description = description;
225 ((ObjectInterface *) clazz->interface)->hash = hash;
226 ((ObjectInterface *) clazz->interface)->isEqual = isEqual;
227
228 ((URLInterface *) clazz->interface)->baseURL = baseURL;
229 ((URLInterface *) clazz->interface)->initWithCharacters = initWithCharacters;
230 ((URLInterface *) clazz->interface)->initWithString = initWithString;
231 ((URLInterface *) clazz->interface)->pathComponents = pathComponents;
232
233 _re = re("([a-z]+)://([^:/\?]+)?(:[0-9]+)?(/[^\?#]+)?([^#]+)?(#.*)?", 0);
234}
235
239static void destroy(Class *clazz) {
240
241 release(_re);
242}
243
248Class *_URL(void) {
249 static Class *clazz;
250 static Once once;
251
252 do_once(&once, {
253 clazz = _initialize(&(const ClassDef) {
254 .name = "URL",
255 .superclass = _Object(),
256 .instanceSize = sizeof(URL),
257 .interfaceOffset = offsetof(URL, interface),
258 .interfaceSize = sizeof(URLInterface),
260 .destroy = destroy,
261 });
262 });
263
264 return clazz;
265}
266
267#undef _Class
ident release(ident obj)
Atomically decrement the given Object's reference count. If the resulting reference count is 0,...
Definition: Class.c:196
Class * _initialize(const ClassDef *def)
Initializes the given Class.
Definition: Class.c:91
#define alloc(type)
Allocate and initialize and instance of type.
Definition: Class.h:159
#define super(type, obj, method,...)
Mutable UTF-8 strings.
Extended POSIX regular expressions.
static void destroy(Class *clazz)
Definition: URL.c:239
static Regexp * _re
Definition: URL.c:130
static void initialize(Class *clazz)
Definition: URL.c:220
Uniform Resource Locators (RFC 3986).
long Once
The Once type.
Definition: Once.h:37
#define do_once(once, block)
Executes the given block at most one time.
Definition: Once.h:43
Immutable arrays.
Definition: Array.h:56
ClassDefs are passed to _initialize via an archetype to initialize a Class.
Definition: Class.h:41
The runtime representation of a Class.
Definition: Class.h:95
ident interface
The interface of the Class.
Definition: Class.h:105
Condition * init(Condition *self)
Initializes this Condition.
Definition: Condition.c:67
Mutable UTF-8 strings.
Definition: MutableString.h:40
void appendString(MutableString *self, const String *string)
Appends the specified String to this MutableString.
MutableString * initWithString(MutableString *self, const String *string)
Initializes this MutableString with the contents of string.
void appendFormat(MutableString *self, const char *fmt,...)
Appends the specified formatted string.
Definition: MutableString.c:89
MutableString * string(void)
Returns a new MutableString.
Object is the root Class of The Objectively Class hierarchy.
Definition: Object.h:46
Class * clazz
Every instance of Object begins with a pointer to its Class.
Definition: Object.h:51
Class * _Object(void)
The Object archetype.
Definition: Object.c:136
Object * copy(const Object *self)
Creates a shallow copy of this Object.
Definition: Array.c:40
String * description(const Object *self)
Definition: Array.c:66
_Bool isEqual(const Object *self, const Object *other)
Tests equality of the other Object.
Definition: Array.c:96
int hash(const Object *self)
Definition: Array.c:80
void dealloc(Object *self)
Frees all resources held by this Object.
Definition: Array.c:50
A location and length into contiguous collections.
Definition: Types.h:54
ssize_t location
The location.
Definition: Types.h:59
size_t length
The length.
Definition: Types.h:64
Extended POSIX regular expressions.
Definition: Regexp.h:43
_Bool matchesCharacters(const Regexp *self, const char *chars, int options, Range **matches)
Matches this regular expression against the given characters.
Definition: Regexp.c:134
OBJECTIVELY_EXPORT Regexp * re(const char *pattern, int options)
A convenience function for instantiating Regexps.
Definition: Regexp.c:219
Immutable UTF-8 strings.
Definition: String.h:69
char * chars
The backing null-terminated UTF-8 encoded character array.
Definition: String.h:85
Array * componentsSeparatedByCharacters(const String *self, const char *chars)
Returns the components of this String that were separated by chars.
Definition: String.c:184
String * initWithCharacters(String *self, const char *chars)
Initializes this String by copying chars.
Definition: String.c:310
String * substring(const String *string, const Range range)
Creates a new String from a subset of this one.
Definition: String.c:539
Uniform Resource Locators (RFC 3986).
Definition: URL.h:44
String * path
The path.
Definition: URL.h:70
unsigned short port
The port.
Definition: URL.h:75
URL * baseURL(const URL *self)
Definition: URL.c:108
Array * pathComponents(const URL *self)
Definition: URL.c:210
String * urlString
The URL String.
Definition: URL.h:90
String * scheme
The scheme, or protocol.
Definition: URL.h:85
String * host
The host.
Definition: URL.h:65
String * fragment
The fragment.
Definition: URL.h:60
String * query
The query.
Definition: URL.h:80
URL * initWithCharacters(URL *self, const char *chars)
Initializes this URL with the specified characters.
Definition: URL.c:136
Class * _URL(void)
The URL archetype.
Definition: URL.c:248