1 /* $NetBSD: libdm-string.c,v 1.1.1.2 2009/12/02 00:26:08 haad Exp $ */ 2 3 /* 4 * Copyright (C) 2006-2007 Red Hat, Inc. All rights reserved. 5 * 6 * This file is part of the device-mapper userspace tools. 7 * 8 * This copyrighted material is made available to anyone wishing to use, 9 * modify, copy, or redistribute it subject to the terms and conditions 10 * of the GNU Lesser General Public License v.2.1. 11 * 12 * You should have received a copy of the GNU Lesser General Public License 13 * along with this program; if not, write to the Free Software Foundation, 14 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 */ 16 17 #include "dmlib.h" 18 #include "libdevmapper.h" 19 20 #include <ctype.h> 21 22 /* 23 * consume characters while they match the predicate function. 24 */ 25 static char *_consume(char *buffer, int (*fn) (int)) 26 { 27 while (*buffer && fn(*buffer)) 28 buffer++; 29 30 return buffer; 31 } 32 33 static int _isword(int c) 34 { 35 return !isspace(c); 36 } 37 38 /* 39 * Split buffer into NULL-separated words in argv. 40 * Returns number of words. 41 */ 42 int dm_split_words(char *buffer, unsigned max, 43 unsigned ignore_comments __attribute((unused)), 44 char **argv) 45 { 46 unsigned arg; 47 48 for (arg = 0; arg < max; arg++) { 49 buffer = _consume(buffer, isspace); 50 if (!*buffer) 51 break; 52 53 argv[arg] = buffer; 54 buffer = _consume(buffer, _isword); 55 56 if (*buffer) { 57 *buffer = '\0'; 58 buffer++; 59 } 60 } 61 62 return arg; 63 } 64 65 /* 66 * Remove hyphen quoting from a component of a name. 67 * NULL-terminates the component and returns start of next component. 68 */ 69 static char *_unquote(char *component) 70 { 71 char *c = component; 72 char *o = c; 73 char *r; 74 75 while (*c) { 76 if (*(c + 1)) { 77 if (*c == '-') { 78 if (*(c + 1) == '-') 79 c++; 80 else 81 break; 82 } 83 } 84 *o = *c; 85 o++; 86 c++; 87 } 88 89 r = (*c) ? c + 1 : c; 90 *o = '\0'; 91 92 return r; 93 } 94 95 int dm_split_lvm_name(struct dm_pool *mem, const char *dmname, 96 char **vgname, char **lvname, char **layer) 97 { 98 if (mem && !(*vgname = dm_pool_strdup(mem, dmname))) 99 return 0; 100 101 _unquote(*layer = _unquote(*lvname = _unquote(*vgname))); 102 103 return 1; 104 } 105 106 /* 107 * On error, up to glibc 2.0.6, snprintf returned -1 if buffer was too small; 108 * From glibc 2.1 it returns number of chars (excl. trailing null) that would 109 * have been written had there been room. 110 * 111 * dm_snprintf reverts to the old behaviour. 112 */ 113 int dm_snprintf(char *buf, size_t bufsize, const char *format, ...) 114 { 115 int n; 116 va_list ap; 117 118 va_start(ap, format); 119 n = vsnprintf(buf, bufsize, format, ap); 120 va_end(ap); 121 122 if (n < 0 || ((unsigned) n + 1 > bufsize)) 123 return -1; 124 125 return n; 126 } 127 128 char *dm_basename(const char *path) 129 { 130 char *p = strrchr(path, '/'); 131 132 return p ? p + 1 : (char *) path; 133 } 134 135 int dm_asprintf(char **result, const char *format, ...) 136 { 137 int n, ok = 0, size = 32; 138 va_list ap; 139 char *buf = dm_malloc(size); 140 141 *result = 0; 142 143 if (!buf) 144 return -1; 145 146 while (!ok) { 147 va_start(ap, format); 148 n = vsnprintf(buf, size, format, ap); 149 if (0 <= n && n < size) 150 ok = 1; 151 else { 152 dm_free(buf); 153 size *= 2; 154 buf = dm_malloc(size); 155 if (!buf) 156 return -1; 157 }; 158 va_end(ap); 159 } 160 161 *result = dm_strdup(buf); 162 dm_free(buf); 163 return n + 1; 164 } 165