Updated Esperanto translation
[gtkhtml.git] / gtkhtml / htmlurl.c
blob057ba5b0df305e1f15c2a76661730ab29ec23f98
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /* htmlurl.c
4 * Copyright (C) 1999 Helix Code, Inc.
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
16 * You should have received a copy of the GNU Library General Public License
17 * along with this library; see the file COPYING.LIB. If not, write to
18 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
21 * Author: Ettore Perazzoli (ettore@helixcode.com) */
23 #include <config.h>
24 #include <stdio.h>
25 #include <string.h>
27 #include "htmlurl.h"
30 static gchar *
31 strdup_nonempty_or_null (const gchar *s)
33 if (s == NULL)
34 return NULL;
35 if (*s == '\0')
36 return NULL;
37 return g_strdup (s);
40 static gchar *
41 strndup_nonempty_or_null (const gchar *s,
42 guint n)
44 if (n == 0)
45 return NULL;
46 if (s == NULL)
47 return NULL;
48 if (*s == '\0')
49 return NULL;
50 return g_strndup (s, n);
53 static const gchar *
54 scan_host_info (HTMLURL *url,
55 const gchar *s)
57 const gchar *slash_ptr;
58 const gchar *at_ptr;
59 const gchar *colon_ptr;
60 const gchar *host_ptr;
61 const gchar *rest_ptr;
63 slash_ptr = strchr (s, '/');
64 if (slash_ptr == NULL) {
65 host_ptr = s;
66 rest_ptr = s + strlen (s);
67 } else {
68 at_ptr = memchr (s, '@', slash_ptr - s);
70 if (at_ptr == NULL) {
71 /* No `@', so it's going to be a hostname only. */
72 host_ptr = s;
73 } else {
74 host_ptr = at_ptr + 1;
76 /* Check if we have a password. */
78 colon_ptr = memchr (s, ':', host_ptr - s);
79 if (colon_ptr == NULL) {
80 url->username = strndup_nonempty_or_null (s, at_ptr - s);
81 } else {
82 url->username = strndup_nonempty_or_null (s, colon_ptr - s);
83 url->password = strndup_nonempty_or_null (colon_ptr + 1,
84 slash_ptr - (colon_ptr + 1));
88 rest_ptr = strchr (host_ptr, '/');
89 if (rest_ptr == NULL)
90 rest_ptr = host_ptr + strlen (host_ptr);
93 /* Look for a port number and set the host name. */
95 colon_ptr = memchr (host_ptr, ':', rest_ptr - host_ptr);
96 if (colon_ptr == NULL) {
97 url->hostname = strndup_nonempty_or_null
98 (host_ptr, rest_ptr - host_ptr);
99 } else {
100 guint port;
102 if (sscanf (colon_ptr + 1, "%ud", &port) == 1)
103 url->port = (guint16) port;
105 url->hostname = strndup_nonempty_or_null
106 (host_ptr, colon_ptr - host_ptr);
109 return rest_ptr;
112 HTMLURL *
113 html_url_new (const gchar *s)
115 HTMLURL *new;
116 const gchar *p;
117 const gchar *path_start;
118 const gchar *s_end;
119 const gchar *reference_ptr;
120 guint s_len;
122 new = g_new (HTMLURL, 1);
123 new->protocol = NULL;
124 new->username = NULL;
125 new->password = NULL;
126 new->hostname = NULL;
127 new->port = 0;
128 new->path = NULL;
129 new->reference = NULL;
131 s_len = strlen (s);
132 if (s_len == 0) {
133 /* The Path can't be NULL. */
134 if (new->path == NULL)
135 new->path = g_strdup ("/");
136 return new;
139 s_end = s + s_len;
141 /* Scan for the protocol part. */
142 /* FIXME I am assuming that the correct regexp for detecting it is
143 * `^[a-zA-Z0-9]:'. */
145 p = s;
146 while ((*p >= 'a' && *p <= 'z')
147 || (*p >= 'A' && *p <= 'Z')
148 || (*p >= '0' && *p <= '9'))
149 p++;
151 if (*p != ':') {
152 /* No protocol. */
153 path_start = s;
154 } else {
155 new->protocol = strndup_nonempty_or_null (s, p - s);
157 /* Check for a host name and a port. */
158 if (p[1] == '/' && p[2] == '/')
159 path_start = scan_host_info (new, p + 3);
160 else
161 path_start = p + 1;
164 /* Look for a reference. */
166 reference_ptr = NULL;
167 p = s_end;
168 while (p != path_start) {
169 p--;
170 if (*p == '#')
171 reference_ptr = p + 1;
174 if (reference_ptr != NULL && *reference_ptr != '\0') {
175 new->reference = strdup_nonempty_or_null (reference_ptr);
176 if (*path_start != '/')
177 new->path = g_strconcat ("/", path_start, NULL);
178 else
179 new->path = g_strndup (path_start,
180 ((reference_ptr - 1)
181 - path_start));
182 } else {
183 #ifdef G_OS_WIN32
184 if (path_start[0] == '/' &&
185 g_ascii_isalpha (path_start[1]) &&
186 path_start[2] == ':')
187 path_start++;
188 #endif
189 new->path = strdup_nonempty_or_null (path_start);
192 /* The Path can't be NULL. */
193 if (new->path == NULL)
194 new->path = g_strdup ("/");
196 #if 0
197 #define STRING_OR_NULL(s) ((s) == NULL ? "(null)" : (s))
198 printf ("*** PARSING `%s'\n", s);
199 printf ("\tprotocol: %s\n", STRING_OR_NULL (new->protocol));
200 printf ("\tusername: %s\n", STRING_OR_NULL (new->username));
201 printf ("\tpassword: %s\n", STRING_OR_NULL (new->password));
202 printf ("\thostname: %s\n", STRING_OR_NULL (new->hostname));
203 printf ("\tport: %u\n", (guint) new->port);
204 printf ("\tpath: %s\n", STRING_OR_NULL (new->path));
205 printf ("\treference: %s\n", STRING_OR_NULL (new->reference));
206 #undef STRING_OR_NULL
207 #endif
209 return new;
212 void
213 html_url_destroy (HTMLURL *url)
215 g_return_if_fail (url != NULL);
217 g_free (url->protocol);
218 g_free (url->username);
219 g_free (url->password);
220 g_free (url->hostname);
221 g_free (url->path);
223 g_free (url);
226 HTMLURL *
227 html_url_dup (const HTMLURL *url,
228 HTMLURLDupFlags flags)
230 HTMLURL *new;
231 gchar *ptr;
233 if (url == NULL)
234 return NULL;
236 new = g_new (HTMLURL, 1);
238 if (flags & HTML_URL_DUP_NOPROTOCOL)
239 new->protocol = NULL;
240 else
241 new->protocol = g_strdup (url->protocol);
243 if (flags & HTML_URL_DUP_NOUSERNAME)
244 new->username = NULL;
245 else
246 new->username = g_strdup (url->username);
248 if (flags & HTML_URL_DUP_NOPASSWORD)
249 new->password = NULL;
250 else
251 new->password = g_strdup (url->password);
253 if (flags & HTML_URL_DUP_NOHOSTNAME)
254 new->hostname = NULL;
255 else
256 new->hostname = g_strdup (url->hostname);
258 if (flags & HTML_URL_DUP_NOPORT)
259 new->port = 0;
260 else
261 new->port = url->port;
263 if (flags & HTML_URL_DUP_NOPATH)
264 new->path = NULL;
265 else
266 new->path = g_strdup (url->path);
268 if (flags & HTML_URL_DUP_NOCGIARGS && new->path) {
269 /* Cut the path after the first '?' */
270 ptr = strchr (new->path, '?');
271 if (ptr)
272 *ptr = 0;
275 if (flags & HTML_URL_DUP_NOREFERENCE)
276 new->reference = NULL;
277 else
278 new->reference = g_strdup (url->reference);
280 return new;
284 #define SET_STR_FUNC(member) \
285 void \
286 html_url_set_##member (HTMLURL *url, const gchar *s) \
288 g_return_if_fail (url != NULL); \
289 g_return_if_fail (s != NULL); \
291 g_free (url->member); \
292 url->member = g_strdup (s); \
295 SET_STR_FUNC (protocol)
296 SET_STR_FUNC (username)
297 SET_STR_FUNC (password)
298 SET_STR_FUNC (hostname)
299 SET_STR_FUNC (path)
300 SET_STR_FUNC (reference)
302 void
303 html_url_set_port (HTMLURL *url,
304 gushort port)
306 g_return_if_fail (url != NULL);
308 url->port = port;
312 #define GET_STR_FUNC(member) \
313 const gchar * \
314 html_url_get_##member (const HTMLURL *url) \
316 g_return_val_if_fail (url != NULL, NULL); \
318 return url->member; \
321 GET_STR_FUNC (protocol)
322 GET_STR_FUNC (username)
323 GET_STR_FUNC (password)
324 GET_STR_FUNC (hostname)
325 GET_STR_FUNC (path)
326 GET_STR_FUNC (reference)
328 gushort
329 html_url_get_port (const HTMLURL *url)
331 g_return_val_if_fail (url != NULL, 0);
333 return url->port;
337 gchar *
338 html_url_to_string (const HTMLURL *url)
340 guint reference_length;
341 guint protocol_length;
342 guint hostname_length;
343 guint username_length;
344 guint password_length;
345 guint path_length;
346 guint port_length;
347 guint length;
348 gchar *port_string;
349 gchar *s;
350 gchar *p;
352 g_return_val_if_fail (url != NULL, NULL);
354 reference_length = 0;
355 protocol_length = 0;
356 hostname_length = 0;
357 username_length = 0;
358 password_length = 0;
359 path_length = 0;
360 port_length = 0;
361 port_string = NULL;
363 length = 0;
364 if (url->protocol != NULL && url->protocol[0] != '\0') {
365 protocol_length = strlen (url->protocol);
366 if (protocol_length > 0) {
367 length += protocol_length;
368 length += 1; /* ':' */
372 if (url->hostname != NULL && url->hostname[0] != '\0') {
373 hostname_length = strlen (url->hostname);
374 length += hostname_length;
375 length += 2; /* '//' */
377 if (url->username != NULL && *url->username != 0) {
378 username_length = strlen (url->username);
379 length += username_length;
380 if (url->password != NULL && *url->password != '\0') {
381 password_length = strlen (url->password);
382 length += 1; /* ':' */
383 length += password_length;
385 length += 1; /* '@' */
388 if (url->port != 0) {
389 port_string = g_strdup_printf ("%d", url->port);
390 port_length = strlen (port_string);
391 port_length += 1; /* ':' */
395 if (url->path != NULL && url->path[0] != '\0') {
396 path_length = strlen (url->path);
397 length += path_length;
399 if (url->reference != NULL && url->reference[0] != '\0') {
401 reference_length = strlen (url->reference);
402 length += 1; /* '#' */
403 length += strlen (url->reference);
407 length += port_length;
409 if (length == 0)
410 return g_strdup ("");
412 length++; /* Final zero. */
414 s = g_malloc (length);
415 p = s;
417 #define APPEND_MEMBER(member) \
418 G_STMT_START{ \
419 memcpy (p, url->member, member##_length); \
420 p += member##_length; \
421 }G_STMT_END
423 #define APPEND_CHAR(c) \
424 *(p++) = c;
426 if (protocol_length != 0) {
427 APPEND_MEMBER (protocol);
428 APPEND_CHAR (':');
431 if (hostname_length != 0) {
432 APPEND_CHAR ('/');
433 APPEND_CHAR ('/');
435 if (username_length != 0) {
436 APPEND_MEMBER (username);
437 if (password_length != 0) {
438 APPEND_CHAR (':');
439 APPEND_MEMBER (password);
441 APPEND_CHAR ('@');
444 APPEND_MEMBER (hostname);
446 if (port_length != 0) {
447 APPEND_CHAR (':');
448 memcpy (p, port_string, port_length);
449 p += port_length - 1;
453 /* Notice that the `path' part is always supposed to start with a
454 * slash, so we don't need to append the slash here. */
456 if (path_length != 0)
457 APPEND_MEMBER (path);
459 if (reference_length != 0) {
460 APPEND_CHAR ('#');
461 APPEND_MEMBER (reference);
464 *p = 0;
466 #undef APPEND
468 return s;
472 #define PATH_SEP '/'
473 #define PATH_SEP_STR "/"
475 static gchar *
476 concat_dir_and_file (const gchar *dir,
477 const gchar *file)
479 /* If the directory name doesn't have a / on the end, we need
480 to add one so we get a proper path to the file */
481 if (*dir && dir[strlen (dir) - 1] != PATH_SEP)
482 return g_strconcat (dir, PATH_SEP_STR, file, NULL);
483 else
484 return g_strconcat (dir, file, NULL);
487 HTMLURL *
488 html_url_append_path (const HTMLURL *url,
489 const gchar *path)
491 HTMLURL *new;
492 gchar *new_path, *tmppath, *ptr;
493 gint i;
495 if (url == NULL)
496 return NULL;
498 new = html_url_dup (url, HTML_URL_DUP_NOPATH);
500 if (url->path == NULL)
501 return NULL;
503 tmppath = g_strdup (url->path);
505 /* Cut the path at the first '?' */
506 if ((ptr = strchr (tmppath, '?')))
507 *ptr = 0;
509 i = strlen (tmppath);
511 /* Remove first '/' from the right */
512 while (i && tmppath[i - 1] != '/')
513 i--;
515 if (i)
516 tmppath[i] = 0;
517 else if (strlen (tmppath) > 1)
518 tmppath[i] = 0;
520 new_path = concat_dir_and_file (tmppath, path);
522 html_url_set_path (new, new_path);
523 g_free (new_path);
524 g_free (tmppath);
526 return new;