root/usr/src/cmd/fm/fmd/common/fmd_string.c
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (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 2004 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

#include <strings.h>
#include <ctype.h>

#include <fmd_string.h>

char *
fmd_strdup(const char *s, int flags)
{
        char *p;

        if (s != NULL)
                p = fmd_alloc(strlen(s) + 1, flags);
        else
                p = NULL;

        if (p != NULL)
                (void) strcpy(p, s);

        return (p);
}

void
fmd_strfree(char *s)
{
        if (s != NULL)
                fmd_free(s, strlen(s) + 1);
}

const char *
fmd_strbasename(const char *s)
{
        const char *p = strrchr(s, '/');

        if (p == NULL)
                return (s);

        return (++p);
}

char *
fmd_strdirname(char *s)
{
        static char slash[] = "/";
        static char dot[] = ".";
        char *p;

        if (s == NULL || *s == '\0')
                return (dot);

        for (p = s + strlen(s); p != s && *--p == '/'; )
                continue;

        if (p == s && *p == '/')
                return (slash);

        while (p != s) {
                if (*--p == '/') {
                        while (*p == '/' && p != s)
                                p--;
                        *++p = '\0';
                        return (s);
                }
        }

        return (dot);
}

ulong_t
fmd_strhash(const char *key)
{
        ulong_t g, h = 0;
        const char *p;

        for (p = key; *p != '\0'; p++) {
                h = (h << 4) + *p;

                if ((g = (h & 0xf0000000)) != 0) {
                        h ^= (g >> 24);
                        h ^= g;
                }
        }

        return (h);
}

/*
 * Transform string s inline, converting each embedded C escape sequence string
 * to the corresponding character.  For example, the substring "\n" is replaced
 * by an inline '\n' character.  The length of the resulting string is returned.
 */
size_t
fmd_stresc2chr(char *s)
{
        char *p, *q, c;
        int esc = 0;
        int x;

        for (p = q = s; (c = *p) != '\0'; p++) {
                if (esc) {
                        switch (c) {
                        case '0':
                        case '1':
                        case '2':
                        case '3':
                        case '4':
                        case '5':
                        case '6':
                        case '7':
                                c -= '0';
                                p++;

                                if (*p >= '0' && *p <= '7') {
                                        c = c * 8 + *p++ - '0';

                                        if (*p >= '0' && *p <= '7')
                                                c = c * 8 + *p - '0';
                                        else
                                                p--;
                                } else
                                        p--;

                                *q++ = c;
                                break;

                        case 'a':
                                *q++ = '\a';
                                break;
                        case 'b':
                                *q++ = '\b';
                                break;
                        case 'f':
                                *q++ = '\f';
                                break;
                        case 'n':
                                *q++ = '\n';
                                break;
                        case 'r':
                                *q++ = '\r';
                                break;
                        case 't':
                                *q++ = '\t';
                                break;
                        case 'v':
                                *q++ = '\v';
                                break;

                        case 'x':
                                for (x = 0; (c = *++p) != '\0'; ) {
                                        if (c >= '0' && c <= '9')
                                                x = x * 16 + c - '0';
                                        else if (c >= 'a' && c <= 'f')
                                                x = x * 16 + c - 'a' + 10;
                                        else if (c >= 'A' && c <= 'F')
                                                x = x * 16 + c - 'A' + 10;
                                        else
                                                break;
                                }
                                *q++ = (char)x;
                                p--;
                                break;

                        case '"':
                        case '\\':
                                *q++ = c;
                                break;
                        default:
                                *q++ = '\\';
                                *q++ = c;
                        }

                        esc = 0;

                } else {
                        if ((esc = c == '\\') == 0)
                                *q++ = c;
                }
        }

        *q = '\0';
        return ((size_t)(q - s));
}

/*
 * We require that identifiers for buffers, statistics, and properties conform
 * to the regular expression [a-zA-Z0-9\-_.].  If check_prefixes is set, we
 * also flag strings that begin with a set of prefixes reserved for use by fmd.
 */
const char *
fmd_strbadid(const char *s, int check_prefixes)
{
        const char *s0 = s;
        int c = *s++;

        while ((c = *s++) != '\0') {
                if (!isupper(c) && !islower(c) &&
                    !isdigit(c) && c != '-' && c != '_' && c != '.')
                        return (s - 1);
        }

        if (check_prefixes && (s0[0] == '_' || s0[0] == '.' ||
            strncmp(s0, "fmd_", 4) == 0 || strncmp(s0, "FMD_", 4) == 0 ||
            strncmp(s0, "fmd.", 4) == 0 || strncmp(s0, "FMD.", 4) == 0))
                return (s0);

        return (NULL);
}

int
fmd_strmatch(const char *s, const char *p)
{
        char c;

        if (p == NULL)
                return (0);

        if (s == NULL)
                s = ""; /* treat NULL string as the empty string */

        do {
                if ((c = *p++) == '\0')
                        return (*s == '\0');

                if (c == '*') {
                        while (*p == '*')
                                p++; /* consecutive *'s can be collapsed */

                        if (*p == '\0')
                                return (1);

                        while (*s != '\0') {
                                if (fmd_strmatch(s++, p) != 0)
                                        return (1);
                        }

                        return (0);
                }
        } while (c == *s++);

        return (0);
}