root/usr/src/lib/print/libpapi-common/common/uri.c
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (the "License").
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */

/*
 * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
 */

/* $Id: uri.c 146 2006-03-24 00:26:54Z njacobs $ */

/*LINTLIBRARY*/

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <errno.h>
#include "uri.h"

/*
 * This will handle the following forms:
 *      scheme:scheme_data
 *      scheme://[[user[:password]@]host[:port]]/path[[#fragment]|[?query]]
 */
int
uri_from_string(char *string, uri_t **uri)
{
        char *ptr;
        uri_t *u;

        if ((string == NULL) || (uri == NULL)) {
                errno = EINVAL;
                return (-1);
        }

        /* find the scheme:scheme_part split */
        if ((ptr = strchr(string, ':')) == NULL) {
                errno = EINVAL;
                return (-1);
        }

        if ((*uri = u = calloc(1, sizeof (*u))) == NULL)
                return (-1);

        u->scheme = strndup(string, ptr - string);

        if ((ptr[1] == '/') && (ptr[2] == '/')) {
                /*
                 * CSTYLED
                 * scheme://[host_part]/[path_part]
                 */
                char *end = NULL, *user = NULL, *host = NULL, *path = NULL;

                string = ptr + 3; /* skip the :// */

                if ((path = end = strchr(string, '/')) == NULL)
                        for (end = string; *end != '\0'; end++)
                                continue;

                u->host_part = strndup(string, end - string);

                for (host = string; host < end; host ++)
                        if (*host == '@') {
                                /* string to host is the user part */
                                u->user_part = strndup(string, host-string);
                                /* host+1 to end is the host part */
                                u->host_part = strndup(host + 1,
                                    end - (host+1));
                                user = string;
                                host++;
                                break;
                        }

                if (user != NULL) {
                        char *password  = NULL;

                        for (password = user; (password < host - 1); password++)
                                if (*password == ':') {
                                        u->password = strndup(password + 1,
                                            host - password - 2);
                                        break;
                                }
                        u->user = strndup(user, password - user);
                } else
                        host = string;

                if (host != NULL) {
                        char *port  = NULL;

                        for (port = host; (port < path); port++)
                                if ((*port == ':') || (*port == '/'))
                                        break;

                        if (port < path) {
                                u->port = strndup(port + 1, path - port - 1);
                        }

                        u->host = strndup(host, port - host);
                }

                if (path != NULL) {
                        char *name = strrchr(path, '/');

                        u->path_part = strdup(path);

                        if (name != NULL) {
                                char *query, *fragment;

                                query = strrchr(name, '?');
                                if ((query != NULL) && (*query != '\0')) {
                                        u->query = strdup(query + 1);
                                        end = query;
                                } else {
                                        for (end = path; *end != '\0'; end++)
                                                continue;
                                }

                                fragment = strrchr(name, '#');
                                if ((fragment != NULL) && (*fragment != '\0')) {
                                        u->fragment = strndup(fragment + 1,
                                            end - fragment - 1);
                                        end = fragment;
                                }

                                u->path = strndup(path, end - path);
                        }
                }
        } else {        /* scheme:scheme_part */
                u->scheme_part = strdup(&ptr[1]);
        }

        if ((u->host_part == NULL) && (u->path_part == NULL) &&
            (u->scheme_part == NULL)) {
                errno = EINVAL;
                uri_free(u);
                *uri = NULL;
                return (-1);
        }

        return (0);
}

int
uri_to_string(uri_t *uri, char *buffer, size_t buflen)
{
        char *uri_ppfix;

        if ((uri == NULL) || (buffer == NULL) || (buflen == 0) ||
            (uri->scheme == NULL) ||
            ((uri->password != NULL) && (uri->user == NULL)) ||
            ((uri->user != NULL) && (uri->host == NULL)) ||
            ((uri->port != NULL) && (uri->host == NULL)) ||
            ((uri->fragment != NULL) && (uri->path == NULL)) ||
            ((uri->query != NULL) && (uri->path == NULL))) {
                errno = EINVAL;
                return (-1);
        }
        if (uri->path == NULL || uri->path[0] == '/')
                uri_ppfix = "";
        else
                uri_ppfix = "/";

        (void) memset(buffer, 0, buflen);

        if (uri->scheme_part == NULL) {
                (void) snprintf(buffer, buflen,
                    "%s://%s%s%s%s%s%s%s%s%s%s%s%s%s",
                    uri->scheme,
                    (uri->user ? uri->user : ""),
                    (uri->password ? ":" : ""),
                    (uri->password ? uri->password : ""),
                    (uri->user ? "@": ""),
                    (uri->host ? uri->host : ""),
                    (uri->port ? ":" : ""),
                    (uri->port ? uri->port : ""),
                    uri_ppfix,
                    (uri->path ? uri->path : ""),
                    (uri->fragment ? "#" : ""),
                    (uri->fragment ? uri->fragment : ""),
                    (uri->query ? "?" : ""),
                    (uri->query ? uri->query : ""));
        } else {
                (void) snprintf(buffer, buflen, "%s:%s", uri->scheme,
                    uri->scheme_part);
        }

        return (0);
}

void
uri_free(uri_t *uri)
{
        if (uri != NULL) {
                if (uri->scheme != NULL)
                        free(uri->scheme);
                if (uri->scheme_part != NULL)
                        free(uri->scheme_part);
                if (uri->user != NULL)
                        free(uri->user);
                if (uri->password != NULL)
                        free(uri->password);
                if (uri->host != NULL)
                        free(uri->host);
                if (uri->port != NULL)
                        free(uri->port);
                if (uri->path != NULL)
                        free(uri->path);
                if (uri->fragment != NULL)
                        free(uri->fragment);
                if (uri->query != NULL)
                        free(uri->query);
                /* help me debug */
                if (uri->user_part != NULL)
                        free(uri->user_part);
                if (uri->host_part != NULL)
                        free(uri->host_part);
                if (uri->path_part != NULL)
                        free(uri->path_part);
                free(uri);
        }
}

#ifdef DEADBEEF
static void
uri_dump(FILE *fp, uri_t *uri)
{
        if (uri != NULL) {
                fprintf(fp, "URI:\n");
                if (uri->scheme != NULL)
                        fprintf(fp, "scheme: %s\n", uri->scheme);
                if (uri->scheme_part != NULL)
                        fprintf(fp, "scheme_part: %s\n", uri->scheme_part);
                if (uri->user != NULL)
                        fprintf(fp, "user: %s\n", uri->user);
                if (uri->password != NULL)
                        fprintf(fp, "password: %s\n", uri->password);
                if (uri->host != NULL)
                        fprintf(fp, "host: %s\n", uri->host);
                if (uri->port != NULL)
                        fprintf(fp, "port: %s\n", uri->port);
                if (uri->path != NULL)
                        fprintf(fp, "path: %s\n", uri->path);
                if (uri->fragment != NULL)
                        fprintf(fp, "fragment: %s\n", uri->fragment);
                if (uri->query != NULL)
                        fprintf(fp, "query: %s\n", uri->query);
                /* help me debug */
                if (uri->user_part != NULL)
                        fprintf(fp, "user_part: %s\n", uri->user_part);
                if (uri->host_part != NULL)
                        fprintf(fp, "host_part: %s\n", uri->host_part);
                if (uri->path_part != NULL)
                        fprintf(fp, "path_part: %s\n", uri->path_part);
                fflush(fp);
        }
}

int
main(int argc, char *argv[])
{
        uri_t *u = NULL;

        if (argc != 2) {
                fprintf(stderr, "Usage: %s uri\n", argv[0]);
                exit(1);
        }

        if (uri_from_string(argv[1], &u) == 0) {
                char buf[BUFSIZ];

                uri_dump(stdout, u);
                uri_to_string(u, buf, sizeof (buf));
                fprintf(stdout, "reconstituted: %s\n", buf);

                uri_to_string(u, buf, 12);
                fprintf(stdout, "reconstituted(12): %s\n", buf);
        } else
                printf(" failed for %s  (%s)\n", argv[1], strerror(errno));

        exit(0);
}
#endif /* DEADBEEF */