source: trunk/third/gtkhtml3/src/htmlurl.c @ 19539

Revision 19539, 10.7 KB checked in by ghudson, 21 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r19538, which included commits to RCS files with non-trunk default branches.
Line 
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2/*  htmlurl.c
3
4    Copyright (C) 1999 Helix Code, Inc.
5
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.
10
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.
15
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., 59 Temple Place - Suite 330,
19    Boston, MA 02111-1307, USA.
20
21    Author: Ettore Perazzoli (ettore@helixcode.com)  */
22
23#include <config.h>
24#include <stdio.h>
25#include <string.h>
26
27#include "htmlurl.h"
28
29
30static gchar *
31strdup_nonempty_or_null (const gchar *s)
32{
33        if (s == NULL)
34                return NULL;
35        if (*s == '\0')
36                return NULL;
37        return g_strdup (s);
38}
39
40static gchar *
41strndup_nonempty_or_null (const gchar *s, guint n)
42{
43        if (n == 0)
44                return NULL;
45        if (s == NULL)
46                return NULL;
47        if (*s == '\0')
48                return NULL;
49        return g_strndup (s, n);
50}
51
52static const gchar *
53scan_host_info (HTMLURL *url, const gchar *s)
54{
55        const gchar *slash_ptr;
56        const gchar *at_ptr;
57        const gchar *colon_ptr;
58        const gchar *host_ptr;
59        const gchar *rest_ptr;
60
61        slash_ptr = strchr (s, '/');
62        if (slash_ptr == NULL) {
63                host_ptr = s;
64                rest_ptr = s + strlen (s);
65        } else {
66                at_ptr = memchr (s, '@', slash_ptr - s);
67
68                if (at_ptr == NULL) {
69                        /* No `@', so it's going to be a hostname only.  */
70                        host_ptr = s;
71                } else {
72                        host_ptr = at_ptr + 1;
73
74                        /* Check if we have a password.  */
75
76                        colon_ptr = memchr (s, ':', host_ptr - s);
77                        if (colon_ptr == NULL) {
78                                url->username  = strndup_nonempty_or_null (s, at_ptr - s);
79                        } else {
80                                url->username = strndup_nonempty_or_null (s, colon_ptr - s);
81                                url->password = strndup_nonempty_or_null (colon_ptr + 1,
82                                                                          slash_ptr - (colon_ptr + 1));
83                        }
84                }
85
86                rest_ptr = strchr (host_ptr, '/');
87                if (rest_ptr == NULL)
88                        rest_ptr = host_ptr + strlen (host_ptr);
89        }
90
91        /* Look for a port number and set the host name.  */
92
93        colon_ptr = memchr (host_ptr, ':', rest_ptr - host_ptr);
94        if (colon_ptr == NULL) {
95                url->hostname = strndup_nonempty_or_null
96                        (host_ptr, rest_ptr - host_ptr);
97        } else {
98                guint port;
99
100                if (sscanf (colon_ptr + 1, "%d", &port) == 1)
101                        url->port = (guint16) port;
102
103                url->hostname = strndup_nonempty_or_null
104                        (host_ptr, colon_ptr - host_ptr);
105        }
106
107        return rest_ptr;
108}
109
110HTMLURL *
111html_url_new (const gchar *s)
112{
113        HTMLURL *new;
114        const gchar *p;
115        const gchar *path_start;
116        const gchar *s_end;
117        const gchar *reference_ptr;
118        guint s_len;
119
120        new = g_new (HTMLURL, 1);
121        new->protocol = NULL;
122        new->username = NULL;
123        new->password = NULL;
124        new->hostname = NULL;
125        new->port = 0;
126        new->path = NULL;
127        new->reference = NULL;
128
129        s_len = strlen (s);
130        if (s_len == 0) {
131                /* The Path can't be NULL.  */
132                if (new->path == NULL)
133                        new->path = g_strdup ("/");
134                return new;
135        }
136
137        s_end = s + s_len;
138
139        /* Scan for the protocol part.  */
140        /* FIXME I am assuming that the correct regexp for detecting it is
141           `^[a-zA-Z0-9]:'.  */
142
143        p = s;
144        while ((*p >= 'a' && *p <= 'z')
145               || (*p >= 'A' && *p <= 'Z')
146               || (*p >= '0' && *p <= '9'))
147                p++;
148
149        if (*p != ':') {
150                /* No protocol.  */
151                path_start = s;
152        } else {
153                new->protocol = strndup_nonempty_or_null (s, p - s);
154
155                /* Check for a host name and a port.  */
156                if (p[1] == '/' && p[2] == '/')
157                        path_start = scan_host_info (new, p + 3);
158                else
159                        path_start = p + 1;
160        }
161
162        /* Look for a reference.  */
163
164        reference_ptr = NULL;
165        p = s_end;
166        while (p != path_start) {
167                p--;
168                if (*p == '#')
169                        reference_ptr = p + 1;
170        }
171
172        if (reference_ptr != NULL && *reference_ptr != '\0') {
173                new->reference = strdup_nonempty_or_null (reference_ptr);
174                if (*path_start != '/')
175                        new->path = g_strconcat ("/", path_start, NULL);
176                else
177                        new->path = g_strndup (path_start,
178                                               ((reference_ptr - 1)
179                                                - path_start));
180        } else {
181                new->path = strdup_nonempty_or_null (path_start);
182        }
183
184        /* The Path can't be NULL.  */
185        if (new->path == NULL)
186                new->path = g_strdup ("/");
187
188#if 0
189#define STRING_OR_NULL(s) ((s) == NULL ? "(null)" : (s))
190        printf ("*** PARSING `%s'\n", s);
191        printf ("\tprotocol: %s\n", STRING_OR_NULL (new->protocol));
192        printf ("\tusername: %s\n", STRING_OR_NULL (new->username));
193        printf ("\tpassword: %s\n", STRING_OR_NULL (new->password));
194        printf ("\thostname: %s\n", STRING_OR_NULL (new->hostname));
195        printf ("\tport: %u\n", (guint) new->port);
196        printf ("\tpath: %s\n", STRING_OR_NULL (new->path));
197        printf ("\treference: %s\n", STRING_OR_NULL (new->reference));
198#undef STRING_OR_NULL
199#endif
200
201        return new;
202}
203
204void
205html_url_destroy (HTMLURL *url)
206{
207        g_return_if_fail (url != NULL);
208
209        g_free (url->protocol);
210        g_free (url->username);
211        g_free (url->password);
212        g_free (url->hostname);
213        g_free (url->path);
214
215        g_free (url);
216}
217
218HTMLURL *
219html_url_dup (const HTMLURL *url, HTMLURLDupFlags flags)
220{
221        HTMLURL *new;
222        gchar *ptr;
223
224        if (url == NULL)
225                return NULL;
226
227        new = g_new (HTMLURL, 1);
228
229        if (flags & HTML_URL_DUP_NOPROTOCOL)
230                new->protocol = NULL;
231        else
232                new->protocol = g_strdup (url->protocol);
233
234        if (flags & HTML_URL_DUP_NOUSERNAME)
235                new->username = NULL;
236        else
237                new->username = g_strdup (url->username);
238
239        if (flags & HTML_URL_DUP_NOPASSWORD)
240                new->password = NULL;
241        else
242                new->password = g_strdup (url->password);
243
244        if (flags & HTML_URL_DUP_NOHOSTNAME)
245                new->hostname = NULL;
246        else
247                new->hostname = g_strdup (url->hostname);
248
249        if (flags & HTML_URL_DUP_NOPORT)
250                new->port = 0;
251        else
252                new->port = url->port;
253
254        if (flags & HTML_URL_DUP_NOPATH)
255                new->path = NULL;
256        else
257                new->path = g_strdup (url->path);
258
259        if (flags & HTML_URL_DUP_NOCGIARGS && new->path) {
260                /* Cut the path after the first '?' */
261                ptr = strchr(new->path, '?');
262                if (ptr)
263                        *ptr = 0;
264        }
265
266        if (flags & HTML_URL_DUP_NOREFERENCE)
267                new->reference = NULL;
268        else
269                new->reference = g_strdup (url->reference);
270
271        return new;
272}
273
274
275#define SET_STR_FUNC(member)                            \
276void                                                    \
277html_url_set_##member (HTMLURL *url, const gchar *s)    \
278{                                                       \
279        g_return_if_fail (url != NULL);                 \
280        g_return_if_fail (s != NULL);                   \
281                                                        \
282        g_free (url->member);                           \
283        url->member = g_strdup (s);                     \
284}
285
286SET_STR_FUNC (protocol)
287SET_STR_FUNC (username)
288SET_STR_FUNC (password)
289SET_STR_FUNC (hostname)
290SET_STR_FUNC (path)
291SET_STR_FUNC (reference)
292
293void
294html_url_set_port (HTMLURL *url, gushort port)
295{
296        g_return_if_fail (url != NULL);
297
298        url->port = port;
299}
300
301
302#define GET_STR_FUNC(member)                    \
303const gchar *                                   \
304html_url_get_##member (const HTMLURL *url)      \
305{                                               \
306        g_return_val_if_fail (url != NULL, 0);  \
307                                                \
308        return url->member;                     \
309}
310
311GET_STR_FUNC (protocol)
312GET_STR_FUNC (username)
313GET_STR_FUNC (password)
314GET_STR_FUNC (hostname)
315GET_STR_FUNC (path)
316GET_STR_FUNC (reference)
317
318gushort
319html_url_get_port (const HTMLURL *url)
320{
321        g_return_val_if_fail (url != NULL, 0);
322
323        return url->port;
324}
325
326
327gchar *
328html_url_to_string (const HTMLURL *url)
329{
330        guint reference_length;
331        guint protocol_length;
332        guint hostname_length;
333        guint username_length;
334        guint password_length;
335        guint path_length;
336        guint port_length;
337        guint length;
338        gchar *port_string;
339        gchar *s;
340        gchar *p;
341
342        g_return_val_if_fail (url != NULL, NULL);
343
344        reference_length = 0;
345        protocol_length = 0;
346        hostname_length = 0;
347        username_length = 0;
348        password_length = 0;
349        path_length = 0;
350        port_length = 0;
351        port_string = NULL;
352
353        length = 0;
354        if (url->protocol != NULL && url->protocol[0] != '\0') {
355                protocol_length = strlen (url->protocol);
356                if (protocol_length > 0) {
357                        length += protocol_length;
358                        length += 1;          /* ':' */
359                }
360        }
361
362        if (url->hostname != NULL && url->hostname[0] != '\0') {
363                hostname_length = strlen (url->hostname);
364                length += hostname_length;
365                length += 2;          /* '//' */
366
367                if (url->username != NULL && *url->username != 0) {
368                        username_length = strlen (url->username);
369                        length += username_length;
370                        if (url->password != NULL && *url->password != '\0') {
371                                password_length = strlen (url->password);
372                                length += 1; /* ':' */
373                                length += password_length;
374                        }
375                        length += 1;  /* '@' */
376                }
377
378                if (url->port != 0) {
379                        port_string = g_strdup_printf ("%d", url->port);
380                        port_length = strlen (port_string);
381                        port_length += 1; /* ':' */
382                }
383        }
384
385        if (url->path != NULL && url->path[0] != '\0') {
386                path_length = strlen (url->path);
387                length += path_length;
388
389                if (url->reference != NULL && url->reference[0] != '\0') {
390
391                        reference_length = strlen (url->reference);
392                        length += 1;  /* '#' */
393                        length += strlen (url->reference);
394                }
395        }
396
397        length += port_length;
398
399        if (length == 0)
400                return g_strdup ("");
401
402        length++;               /* Final zero.  */
403
404        s = g_malloc (length);
405        p = s;
406
407#define APPEND_MEMBER(member)                                   \
408        G_STMT_START{                                           \
409                memcpy (p, url->member, member##_length);       \
410                p += member##_length;                           \
411        }G_STMT_END
412
413#define APPEND_CHAR(c)                          \
414        *(p++) = c;
415
416
417        if (protocol_length != 0) {
418                APPEND_MEMBER (protocol);
419                APPEND_CHAR (':');
420        }
421
422        if (hostname_length != 0) {
423                APPEND_CHAR ('/');
424                APPEND_CHAR ('/');
425
426                if (username_length != 0) {
427                        APPEND_MEMBER (username);
428                        if (password_length != 0) {
429                                APPEND_CHAR (':');
430                                APPEND_MEMBER (password);
431                        }
432                        APPEND_CHAR ('@');
433                }
434
435                APPEND_MEMBER (hostname);
436
437                if (port_length != 0) {
438                        APPEND_CHAR (':');
439                        memcpy (p, port_string, port_length);
440                        p += port_length - 1;
441                }
442        }
443
444        /* Notice that the `path' part is always supposed to start with a
445           slash, so we don't need to append the slash here.  */
446
447        if (path_length != 0)
448                APPEND_MEMBER (path);
449
450        if (reference_length != 0) {
451                APPEND_CHAR ('#');
452                APPEND_MEMBER (reference);
453        }
454
455        *p = 0;
456
457#undef APPEND
458
459        return s;
460}
461
462
463#define PATH_SEP '/'
464#define PATH_SEP_STR "/"
465
466static char *
467concat_dir_and_file (const char *dir, const char *file)
468{
469        /* If the directory name doesn't have a / on the end, we need
470           to add one so we get a proper path to the file */
471        if (*dir && dir [strlen(dir) - 1] != PATH_SEP)
472                return g_strconcat (dir, PATH_SEP_STR, file, NULL);
473        else
474                return g_strconcat (dir, file, NULL);
475}
476
477HTMLURL *
478html_url_append_path (const HTMLURL *url,
479                      const gchar *path)
480{
481        HTMLURL *new;
482        gchar *new_path, *tmppath, *ptr;
483        int i;
484
485        new = html_url_dup (url, HTML_URL_DUP_NOPATH);
486
487        g_assert(url->path != NULL);
488       
489        tmppath = g_strdup(url->path);
490
491        /* Cut the path at the first '?' */
492        if((ptr = strchr(tmppath, '?')))
493                *ptr = 0;
494
495        i = strlen(tmppath);
496
497        /* Remove first '/' from the right */
498        while(i && tmppath[i-1] != '/')
499                i--;
500
501        if(i)
502                tmppath[i] = 0;
503        else if(strlen(tmppath) > 1)
504                tmppath[i] = 0;
505
506        new_path = concat_dir_and_file (tmppath, path);
507
508        html_url_set_path (new, new_path);
509        g_free (new_path);
510        g_free (tmppath);
511
512        return new;
513}
Note: See TracBrowser for help on using the repository browser.