1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License, Version 1.0 only
   6  * (the "License").  You may not use this file except in compliance
   7  * with the License.
   8  *
   9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  10  * or http://www.opensolaris.org/os/licensing.
  11  * See the License for the specific language governing permissions
  12  * and limitations under the License.
  13  *
  14  * When distributing Covered Code, include this CDDL HEADER in each
  15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  16  * If applicable, add the following below this CDDL HEADER, with the
  17  * fields enclosed by brackets "[]" replaced with your own identifying
  18  * information: Portions Copyright [yyyy] [name of copyright owner]
  19  *
  20  * CDDL HEADER END
  21  */
  22 /*
  23  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  */
  26 /*
  27  * Copyright (c) 2013, Joyent, Inc. All rights reserved.
  28  */
  29 
  30 #include <strings.h>
  31 #include <ctype.h>
  32 #include <fm/libtopo.h>
  33 #include <fm/topo_mod.h>
  34 #include <topo_alloc.h>
  35 
  36 char *
  37 topo_hdl_strdup(topo_hdl_t *thp, const char *s)
  38 {
  39         char *p;
  40 
  41         if (s != NULL)
  42                 p = topo_hdl_alloc(thp, strlen(s) + 1);
  43         else
  44                 p = NULL;
  45 
  46         if (p != NULL)
  47                 (void) strcpy(p, s);
  48 
  49         return (p);
  50 }
  51 
  52 void
  53 topo_hdl_strfree(topo_hdl_t *thp, char *s)
  54 {
  55         if (s != NULL)
  56                 topo_hdl_free(thp, s, strlen(s) + 1);
  57 }
  58 
  59 char *
  60 topo_hdl_strsplit(topo_hdl_t *hdl, const char *input, const char *sep,
  61     char **lastp)
  62 {
  63         size_t seplen = strlen(sep);
  64         const char *scanstart;
  65         char *token;
  66         char *ret;
  67 
  68         if (input != NULL) {
  69                 /*
  70                  * Start scanning at beginning of input:
  71                  */
  72                 scanstart = input;
  73         } else if (*lastp == NULL) {
  74                 /*
  75                  * If we have already finished scanning, return NULL.
  76                  */
  77                 return (NULL);
  78         } else {
  79                 /*
  80                  * Otherwise, start scanning where we left off:
  81                  */
  82                 scanstart = *lastp;
  83         }
  84 
  85         token = strstr(scanstart, sep);
  86         if (token != NULL) {
  87                 /*
  88                  * We still have a separator, so advance the next-start
  89                  * pointer past it:
  90                  */
  91                 *lastp = token + seplen;
  92                 /*
  93                  * Copy out this element.  The buffer must fit the string
  94                  * exactly, so that topo_hdl_strfree() can determine its
  95                  * size with strlen().
  96                  */
  97                 ret = topo_hdl_alloc(hdl, token - scanstart + 1);
  98                 (void) strncpy(ret, scanstart, token - scanstart);
  99                 ret[token - scanstart] = '\0';
 100         } else {
 101                 /*
 102                  * We have no separator, so this is the last element:
 103                  */
 104                 *lastp = NULL;
 105                 ret = topo_hdl_strdup(hdl, scanstart);
 106         }
 107 
 108         return (ret);
 109 }
 110 
 111 char *
 112 topo_mod_strdup(topo_mod_t *mod, const char *s)
 113 {
 114         return (topo_hdl_strdup(mod->tm_hdl, s));
 115 }
 116 
 117 void
 118 topo_mod_strfree(topo_mod_t *mod, char *s)
 119 {
 120         topo_hdl_strfree(mod->tm_hdl, s);
 121 }
 122 
 123 char *
 124 topo_mod_strsplit(topo_mod_t *mod, const char *input, const char *sep,
 125     char **lastp)
 126 {
 127         return (topo_hdl_strsplit(mod->tm_hdl, input, sep, lastp));
 128 }
 129 
 130 const char *
 131 topo_strbasename(const char *s)
 132 {
 133         const char *p = strrchr(s, '/');
 134 
 135         if (p == NULL)
 136                 return (s);
 137 
 138         return (++p);
 139 }
 140 
 141 char *
 142 topo_strdirname(char *s)
 143 {
 144         static char slash[] = "/";
 145         static char dot[] = ".";
 146         char *p;
 147 
 148         if (s == NULL || *s == '\0')
 149                 return (dot);
 150 
 151         for (p = s + strlen(s); p != s && *--p == '/'; )
 152                 continue;
 153 
 154         if (p == s && *p == '/')
 155                 return (slash);
 156 
 157         while (p != s) {
 158                 if (*--p == '/') {
 159                         while (*p == '/' && p != s)
 160                                 p--;
 161                         *++p = '\0';
 162                         return (s);
 163                 }
 164         }
 165 
 166         return (dot);
 167 }
 168 
 169 ulong_t
 170 topo_strhash(const char *key)
 171 {
 172         ulong_t g, h = 0;
 173         const char *p;
 174 
 175         for (p = key; *p != '\0'; p++) {
 176                 h = (h << 4) + *p;
 177 
 178                 if ((g = (h & 0xf0000000)) != 0) {
 179                         h ^= (g >> 24);
 180                         h ^= g;
 181                 }
 182         }
 183 
 184         return (h);
 185 }
 186 
 187 /*
 188  * Transform string s inline, converting each embedded C escape sequence string
 189  * to the corresponding character.  For example, the substring "\n" is replaced
 190  * by an inline '\n' character.  The length of the resulting string is returned.
 191  */
 192 size_t
 193 topo_stresc2chr(char *s)
 194 {
 195         char *p, *q, c;
 196         int esc = 0;
 197         int x;
 198 
 199         for (p = q = s; (c = *p) != '\0'; p++) {
 200                 if (esc) {
 201                         switch (c) {
 202                         case '0':
 203                         case '1':
 204                         case '2':
 205                         case '3':
 206                         case '4':
 207                         case '5':
 208                         case '6':
 209                         case '7':
 210                                 c -= '0';
 211                                 p++;
 212 
 213                                 if (*p >= '0' && *p <= '7') {
 214                                         c = c * 8 + *p++ - '0';
 215 
 216                                         if (*p >= '0' && *p <= '7')
 217                                                 c = c * 8 + *p - '0';
 218                                         else
 219                                                 p--;
 220                                 } else
 221                                         p--;
 222 
 223                                 *q++ = c;
 224                                 break;
 225 
 226                         case 'a':
 227                                 *q++ = '\a';
 228                                 break;
 229                         case 'b':
 230                                 *q++ = '\b';
 231                                 break;
 232                         case 'f':
 233                                 *q++ = '\f';
 234                                 break;
 235                         case 'n':
 236                                 *q++ = '\n';
 237                                 break;
 238                         case 'r':
 239                                 *q++ = '\r';
 240                                 break;
 241                         case 't':
 242                                 *q++ = '\t';
 243                                 break;
 244                         case 'v':
 245                                 *q++ = '\v';
 246                                 break;
 247 
 248                         case 'x':
 249                                 for (x = 0; (c = *++p) != '\0'; ) {
 250                                         if (c >= '0' && c <= '9')
 251                                                 x = x * 16 + c - '0';
 252                                         else if (c >= 'a' && c <= 'f')
 253                                                 x = x * 16 + c - 'a' + 10;
 254                                         else if (c >= 'A' && c <= 'F')
 255                                                 x = x * 16 + c - 'A' + 10;
 256                                         else
 257                                                 break;
 258                                 }
 259                                 *q++ = (char)x;
 260                                 p--;
 261                                 break;
 262 
 263                         case '"':
 264                         case '\\':
 265                                 *q++ = c;
 266                                 break;
 267                         default:
 268                                 *q++ = '\\';
 269                                 *q++ = c;
 270                         }
 271 
 272                         esc = 0;
 273 
 274                 } else {
 275                         if ((esc = c == '\\') == 0)
 276                                 *q++ = c;
 277                 }
 278         }
 279 
 280         *q = '\0';
 281         return ((size_t)(q - s));
 282 }
 283 
 284 int
 285 topo_strmatch(const char *s, const char *p)
 286 {
 287         char c;
 288 
 289         if (p == NULL)
 290                 return (0);
 291 
 292         if (s == NULL)
 293                 s = ""; /* treat NULL string as the empty string */
 294 
 295         do {
 296                 if ((c = *p++) == '\0')
 297                         return (*s == '\0');
 298 
 299                 if (c == '*') {
 300                         while (*p == '*')
 301                                 p++; /* consecutive *'s can be collapsed */
 302 
 303                         if (*p == '\0')
 304                                 return (1);
 305 
 306                         while (*s != '\0') {
 307                                 if (topo_strmatch(s++, p) != 0)
 308                                         return (1);
 309                         }
 310 
 311                         return (0);
 312                 }
 313         } while (c == *s++);
 314 
 315         return (0);
 316 }