Whamcloud - gitweb
LU-1146 build: batch update copyright messages
[fs/lustre-release.git] / libcfs / libcfs / libcfs_string.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  * GPL HEADER START
5  *
6  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License version 2 only,
10  * as published by the Free Software Foundation.
11  *
12  * This program is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * General Public License version 2 for more details (a copy is included
16  * in the LICENSE file that accompanied this code).
17  *
18  * You should have received a copy of the GNU General Public License
19  * version 2 along with this program; If not, see
20  * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
21  *
22  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
23  * CA 95054 USA or visit www.sun.com if you need additional information or
24  * have any questions.
25  *
26  * GPL HEADER END
27  */
28 /*
29  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
30  * Use is subject to license terms.
31  *
32  * Copyright (c) 2012, Whamcloud, Inc.
33  */
34 /*
35  * This file is part of Lustre, http://www.lustre.org/
36  * Lustre is a trademark of Sun Microsystems, Inc.
37  *
38  * String manipulation functions.
39  *
40  * libcfs/libcfs/libcfs_string.c
41  *
42  * Author: Nathan Rutman <nathan.rutman@sun.com>
43  */
44
45 #ifndef EXPORT_SYMTAB
46 # define EXPORT_SYMTAB
47 #endif
48
49 #include <libcfs/libcfs.h>
50
51 /* non-0 = don't match */
52 static int cfs_strncasecmp(const char *s1, const char *s2, size_t n)
53 {
54         if (s1 == NULL || s2 == NULL)
55                 return 1;
56
57         if (n == 0)
58                 return 0;
59
60         while (n-- != 0 && tolower(*s1) == tolower(*s2)) {
61                 if (n == 0 || *s1 == '\0' || *s2 == '\0')
62                         break;
63                 s1++;
64                 s2++;
65         }
66
67         return tolower(*(unsigned char *)s1) - tolower(*(unsigned char *)s2);
68 }
69
70 /* Convert a text string to a bitmask */
71 int cfs_str2mask(const char *str, const char *(*bit2str)(int bit),
72                  int *oldmask, int minmask, int allmask)
73 {
74         const char *debugstr;
75         char op = 0;
76         int newmask = minmask, i, len, found = 0;
77         ENTRY;
78
79         /* <str> must be a list of tokens separated by whitespace
80          * and optionally an operator ('+' or '-').  If an operator
81          * appears first in <str>, '*oldmask' is used as the starting point
82          * (relative), otherwise minmask is used (absolute).  An operator
83          * applies to all following tokens up to the next operator. */
84         while (*str != 0) {
85                 while (isspace(*str))
86                         str++;
87                 if (*str == 0)
88                         break;
89                 if (*str == '+' || *str == '-') {
90                         op = *str++;
91                         if (!found)
92                                 /* only if first token is relative */
93                                 newmask = *oldmask;
94                         while (isspace(*str))
95                                 str++;
96                         if (*str == 0)          /* trailing op */
97                                 return -EINVAL;
98                 }
99
100                 /* find token length */
101                 for (len = 0; str[len] != 0 && !isspace(str[len]) &&
102                       str[len] != '+' && str[len] != '-'; len++);
103
104                 /* match token */
105                 found = 0;
106                 for (i = 0; i < 32; i++) {
107                         debugstr = bit2str(i);
108                         if (debugstr != NULL &&
109                             strlen(debugstr) == len &&
110                             cfs_strncasecmp(str, debugstr, len) == 0) {
111                                 if (op == '-')
112                                         newmask &= ~(1 << i);
113                                 else
114                                         newmask |= (1 << i);
115                                 found = 1;
116                                 break;
117                         }
118                 }
119                 if (!found && len == 3 &&
120                     (cfs_strncasecmp(str, "ALL", len) == 0)) {
121                         if (op == '-')
122                                 newmask = minmask;
123                         else
124                                 newmask = allmask;
125                         found = 1;
126                 }
127                 if (!found) {
128                         CWARN("unknown mask '%.*s'.\n"
129                               "mask usage: [+|-]<all|type> ...\n", len, str);
130                         return -EINVAL;
131                 }
132                 str += len;
133         }
134
135         *oldmask = newmask;
136         return 0;
137 }
138 EXPORT_SYMBOL(cfs_str2mask);
139
140 /* Duplicate a string in a platform-independent way */
141 char *cfs_strdup(const char *str, u_int32_t flags)
142 {
143         size_t lenz; /* length of str + zero byte */
144         char *dup_str;
145
146         lenz = strlen(str) + 1;
147
148         dup_str = cfs_alloc(lenz, flags);
149         if (dup_str == NULL)
150                 return NULL;
151
152         memcpy(dup_str, str, lenz);
153
154         return dup_str;
155 }
156 EXPORT_SYMBOL(cfs_strdup);
157
158 /**
159  * cfs_{v}snprintf() return the actual size that is printed rather than
160  * the size that would be printed in standard functions.
161  */
162 /* safe vsnprintf */
163 int cfs_vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
164 {
165         int i;
166
167         LASSERT(size > 0);
168         i = vsnprintf(buf, size, fmt, args);
169
170         return  (i >= size ? size - 1 : i);
171 }
172 EXPORT_SYMBOL(cfs_vsnprintf);
173
174 /* safe snprintf */
175 int cfs_snprintf(char *buf, size_t size, const char *fmt, ...)
176 {
177         va_list args;
178         int i;
179
180         va_start(args, fmt);
181         i = cfs_vsnprintf(buf, size, fmt, args);
182         va_end(args);
183
184         return  i;
185 }
186 EXPORT_SYMBOL(cfs_snprintf);
187
188 /* get the first string out of @str */
189 char *cfs_firststr(char *str, size_t size)
190 {
191         size_t i = 0;
192         char  *end;
193
194         /* trim leading spaces */
195         while (i < size && *str && isspace(*str)) {
196                 ++i;
197                 ++str;
198         }
199
200         /* string with all spaces */
201         if (*str == '\0')
202                 goto out;
203
204         end = str;
205         while (i < size && *end != '\0' && !isspace(*end)) {
206                 ++i;
207                 ++end;
208         }
209
210         *end= '\0';
211 out:
212         return str;
213 }
214 EXPORT_SYMBOL(cfs_firststr);