1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
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) */
31 strdup_nonempty_or_null (const gchar
*s
)
41 strndup_nonempty_or_null (const gchar
*s
,
50 return g_strndup (s
, n
);
54 scan_host_info (HTMLURL
*url
,
57 const gchar
*slash_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
) {
66 rest_ptr
= s
+ strlen (s
);
68 at_ptr
= memchr (s
, '@', slash_ptr
- s
);
71 /* No `@', so it's going to be a hostname only. */
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
);
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
, '/');
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
);
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
);
113 html_url_new (const gchar
*s
)
117 const gchar
*path_start
;
119 const gchar
*reference_ptr
;
122 new = g_new (HTMLURL
, 1);
123 new->protocol
= NULL
;
124 new->username
= NULL
;
125 new->password
= NULL
;
126 new->hostname
= NULL
;
129 new->reference
= NULL
;
133 /* The Path can't be NULL. */
134 if (new->path
== NULL
)
135 new->path
= g_strdup ("/");
141 /* Scan for the protocol part. */
142 /* FIXME I am assuming that the correct regexp for detecting it is
143 * `^[a-zA-Z0-9]:'. */
146 while ((*p
>= 'a' && *p
<= 'z')
147 || (*p
>= 'A' && *p
<= 'Z')
148 || (*p
>= '0' && *p
<= '9'))
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);
164 /* Look for a reference. */
166 reference_ptr
= NULL
;
168 while (p
!= path_start
) {
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
);
179 new->path
= g_strndup (path_start
,
184 if (path_start
[0] == '/' &&
185 g_ascii_isalpha (path_start
[1]) &&
186 path_start
[2] == ':')
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 ("/");
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
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
);
227 html_url_dup (const HTMLURL
*url
,
228 HTMLURLDupFlags flags
)
236 new = g_new (HTMLURL
, 1);
238 if (flags
& HTML_URL_DUP_NOPROTOCOL
)
239 new->protocol
= NULL
;
241 new->protocol
= g_strdup (url
->protocol
);
243 if (flags
& HTML_URL_DUP_NOUSERNAME
)
244 new->username
= NULL
;
246 new->username
= g_strdup (url
->username
);
248 if (flags
& HTML_URL_DUP_NOPASSWORD
)
249 new->password
= NULL
;
251 new->password
= g_strdup (url
->password
);
253 if (flags
& HTML_URL_DUP_NOHOSTNAME
)
254 new->hostname
= NULL
;
256 new->hostname
= g_strdup (url
->hostname
);
258 if (flags
& HTML_URL_DUP_NOPORT
)
261 new->port
= url
->port
;
263 if (flags
& HTML_URL_DUP_NOPATH
)
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
, '?');
275 if (flags
& HTML_URL_DUP_NOREFERENCE
)
276 new->reference
= NULL
;
278 new->reference
= g_strdup (url
->reference
);
284 #define SET_STR_FUNC(member) \
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
)
300 SET_STR_FUNC (reference
)
303 html_url_set_port (HTMLURL
*url
,
306 g_return_if_fail (url
!= NULL
);
312 #define GET_STR_FUNC(member) \
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
)
326 GET_STR_FUNC (reference
)
329 html_url_get_port (const HTMLURL
*url
)
331 g_return_val_if_fail (url
!= NULL
, 0);
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
;
352 g_return_val_if_fail (url
!= NULL
, NULL
);
354 reference_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
;
410 return g_strdup ("");
412 length
++; /* Final zero. */
414 s
= g_malloc (length
);
417 #define APPEND_MEMBER(member) \
419 memcpy (p, url->member, member##_length); \
420 p += member##_length; \
423 #define APPEND_CHAR(c) \
426 if (protocol_length
!= 0) {
427 APPEND_MEMBER (protocol
);
431 if (hostname_length
!= 0) {
435 if (username_length
!= 0) {
436 APPEND_MEMBER (username
);
437 if (password_length
!= 0) {
439 APPEND_MEMBER (password
);
444 APPEND_MEMBER (hostname
);
446 if (port_length
!= 0) {
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) {
461 APPEND_MEMBER (reference
);
473 #define PATH_SEP_STR "/"
476 concat_dir_and_file (const gchar
*dir
,
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
);
484 return g_strconcat (dir
, file
, NULL
);
488 html_url_append_path (const HTMLURL
*url
,
492 gchar
*new_path
, *tmppath
, *ptr
;
498 new = html_url_dup (url
, HTML_URL_DUP_NOPATH
);
500 if (url
->path
== NULL
)
503 tmppath
= g_strdup (url
->path
);
505 /* Cut the path at the first '?' */
506 if ((ptr
= strchr (tmppath
, '?')))
509 i
= strlen (tmppath
);
511 /* Remove first '/' from the right */
512 while (i
&& tmppath
[i
- 1] != '/')
517 else if (strlen (tmppath
) > 1)
520 new_path
= concat_dir_and_file (tmppath
, path
);
522 html_url_set_path (new, new_path
);