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 {
  74                 /*
  75                  * If we have already finished scanning, return NULL.
  76                  */
  77                 if (*lastp == NULL)
  78                         return (NULL);
  79 
  80                 /*
  81                  * Otherwise, start scanning where we left off:
  82                  */
  83                 scanstart = *lastp;
  84         }
  85 
  86         token = strstr(scanstart, sep);
  87         if (token != NULL) {
  88                 /*
  89                  * We still have a separator, so advance the next-start
  90                  * pointer past it:
  91                  */
  92                 *lastp = token + seplen;
  93                 /*
  94                  * Copy out this element:
  95                  */
  96                 ret = topo_hdl_alloc(hdl, token - scanstart + 1);
  97                 (void) strncpy(ret, scanstart, token - scanstart);
  98                 ret[token - scanstart] = '\0';
  99         } else {
 100                 /*
 101                  * We have no separator, so this is the last element:
 102                  */
 103                 *lastp = NULL;
 104                 ret = topo_hdl_strdup(hdl, scanstart);
 105         }
 106 
 107         return (ret);
 108 }
 109 
 110 char *
 111 topo_mod_strdup(topo_mod_t *mod, const char *s)
 112 {
 113         return (topo_hdl_strdup(mod->tm_hdl, s));
 114 }
 115 
 116 void
 117 topo_mod_strfree(topo_mod_t *mod, char *s)
 118 {
 119         topo_hdl_strfree(mod->tm_hdl, s);
 120 }
 121 
 122 char *
 123 topo_mod_strsplit(topo_mod_t *mod, const char *input, const char *sep,
 124     char **lastp)
 125 {
 126         return (topo_hdl_strsplit(mod->tm_hdl, input, sep, lastp));
 127 }
 128 
 129 const char *
 130 topo_strbasename(const char *s)
 131 {
 132         const char *p = strrchr(s, '/');
 133 
 134         if (p == NULL)
 135                 return (s);
 136 
 137         return (++p);
 138 }
 139 
 140 char *
 141 topo_strdirname(char *s)
 142 {
 143         static char slash[] = "/";
 144         static char dot[] = ".";
 145         char *p;
 146 
 147         if (s == NULL || *s == '\0')
 148                 return (dot);
 149 
 150         for (p = s + strlen(s); p != s && *--p == '/'; )
 151                 continue;
 152 
 153         if (p == s && *p == '/')
 154                 return (slash);
 155 
 156         while (p != s) {
 157                 if (*--p == '/') {
 158                         while (*p == '/' && p != s)
 159                                 p--;
 160                         *++p = '\0';
 161                         return (s);
 162                 }
 163         }
 164 
 165         return (dot);
 166 }
 167 
 168 ulong_t
 169 topo_strhash(const char *key)
 170 {
 171         ulong_t g, h = 0;
 172         const char *p;
 173 
 174         for (p = key; *p != '\0'; p++) {
 175                 h = (h << 4) + *p;
 176 
 177                 if ((g = (h & 0xf0000000)) != 0) {
 178                         h ^= (g >> 24);
 179                         h ^= g;
 180                 }
 181         }
 182 
 183         return (h);
 184 }
 185 
 186 /*
 187  * Transform string s inline, converting each embedded C escape sequence string
 188  * to the corresponding character.  For example, the substring "\n" is replaced
 189  * by an inline '\n' character.  The length of the resulting string is returned.
 190  */
 191 size_t
 192 topo_stresc2chr(char *s)
 193 {
 194         char *p, *q, c;
 195         int esc = 0;
 196         int x;
 197 
 198         for (p = q = s; (c = *p) != '\0'; p++) {
 199                 if (esc) {
 200                         switch (c) {
 201                         case '0':
 202                         case '1':
 203                         case '2':
 204                         case '3':
 205                         case '4':
 206                         case '5':
 207                         case '6':
 208                         case '7':
 209                                 c -= '0';
 210                                 p++;
 211 
 212                                 if (*p >= '0' && *p <= '7') {
 213                                         c = c * 8 + *p++ - '0';
 214 
 215                                         if (*p >= '0' && *p <= '7')
 216                                                 c = c * 8 + *p - '0';
 217                                         else
 218                                                 p--;
 219                                 } else
 220                                         p--;
 221 
 222                                 *q++ = c;
 223                                 break;
 224 
 225                         case 'a':
 226                                 *q++ = '\a';
 227                                 break;
 228                         case 'b':
 229                                 *q++ = '\b';
 230                                 break;
 231                         case 'f':
 232                                 *q++ = '\f';
 233                                 break;
 234                         case 'n':
 235                                 *q++ = '\n';
 236                                 break;
 237                         case 'r':
 238                                 *q++ = '\r';
 239                                 break;
 240                         case 't':
 241                                 *q++ = '\t';
 242                                 break;
 243                         case 'v':
 244                                 *q++ = '\v';
 245                                 break;
 246 
 247                         case 'x':
 248                                 for (x = 0; (c = *++p) != '\0'; ) {
 249                                         if (c >= '0' && c <= '9')
 250                                                 x = x * 16 + c - '0';
 251                                         else if (c >= 'a' && c <= 'f')
 252                                                 x = x * 16 + c - 'a' + 10;
 253                                         else if (c >= 'A' && c <= 'F')
 254                                                 x = x * 16 + c - 'A' + 10;
 255                                         else
 256                                                 break;
 257                                 }
 258                                 *q++ = (char)x;
 259                                 p--;
 260                                 break;
 261 
 262                         case '"':
 263                         case '\\':
 264                                 *q++ = c;
 265                                 break;
 266                         default:
 267                                 *q++ = '\\';
 268                                 *q++ = c;
 269                         }
 270 
 271                         esc = 0;
 272 
 273                 } else {
 274                         if ((esc = c == '\\') == 0)
 275                                 *q++ = c;
 276                 }
 277         }
 278 
 279         *q = '\0';
 280         return ((size_t)(q - s));
 281 }
 282 
 283 int
 284 topo_strmatch(const char *s, const char *p)
 285 {
 286         char c;
 287 
 288         if (p == NULL)
 289                 return (0);
 290 
 291         if (s == NULL)
 292                 s = ""; /* treat NULL string as the empty string */
 293 
 294         do {
 295                 if ((c = *p++) == '\0')
 296                         return (*s == '\0');
 297 
 298                 if (c == '*') {
 299                         while (*p == '*')
 300                                 p++; /* consecutive *'s can be collapsed */
 301 
 302                         if (*p == '\0')
 303                                 return (1);
 304 
 305                         while (*s != '\0') {
 306                                 if (topo_strmatch(s++, p) != 0)
 307                                         return (1);
 308                         }
 309 
 310                         return (0);
 311                 }
 312         } while (c == *s++);
 313 
 314         return (0);
 315 }