1 /* 2 * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. 3 * 4 * This program is free software; you can redistribute it and/or modify it 5 * under the terms of version 2 of the GNU General Public License as 6 * published by the Free Software Foundation. 7 * 8 * This program is distributed in the hope that it would be useful, but 9 * WITHOUT ANY WARRANTY; without even the implied warranty of 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 11 * 12 * Further, this software is distributed without any warranty that it is 13 * free of the rightful claim of any third person regarding infringement 14 * or the like. Any license provided herein, whether implied or 15 * otherwise, applies only to this software file. Patent licenses, if 16 * any, provided herein do not apply to combinations of this program with 17 * other software, or any other product whatsoever. 18 * 19 * You should have received a copy of the GNU General Public License along 20 * with this program; if not, write the Free Software Foundation, Inc., 21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 22 * 23 * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, 24 * Mountain View, CA 94043, or: 25 * 26 * http://www.sgi.com 27 * 28 * For further information regarding this notice, see: 29 * 30 * http://oss.sgi.com/projects/GenInfo/NoticeExplan/ 31 * 32 */ 33 /* $Id: splitstr.c,v 1.2 2000/09/21 20:42:31 nstraz Exp $ */ 34 /* 35 * Synopsis 36 * 37 * const char **splitstr(const char *str, const char *separator, int *argcount) 38 * 39 * Description 40 * This function splits a string (str) into components that are separated by 41 * one or more of the characters in the (separator) string. An array of 42 * strings is returned, along with argcount being set to the number of strings 43 * found. Argcount can be NULL. There will always be a NULL element in the 44 * array after the last valid element. If an error occurs, NULL will be 45 * returned and argcount will be set to zero. 46 * 47 * To rid yourself of the memory allocated for splitstr(), pass the return 48 * value from splitstr() unmodified to splitstr_free(): 49 * 50 * void splitstr_free( const char ** return_from_splitstr ); 51 * 52 */ 53 #include <stdio.h> 54 #include <stdlib.h> 55 #include <string.h> /* for string functions */ 56 #ifdef UNIT_TEST 57 #include <assert.h> 58 #endif /* UNIT_TEST */ 59 #include "splitstr.h" 60 61 const char **splitstr(const char *str, const char *separator, int *argcount) 62 { 63 char *arg_string = NULL, **arg_array = NULL, *cur_tok = NULL; 64 65 int num_toks = 0, max_toks = 20, i; 66 67 /* 68 * In most recoverable errors, if argcount is not NULL, 69 * set argcount to 0. Then return NULL. 70 */ 71 if (str == NULL) { 72 if (argcount != NULL) 73 *argcount = 0; 74 return (NULL); 75 } 76 77 /* 78 * set aside temporary space to work on the string. 79 */ 80 arg_string = strdup(str); 81 82 if (arg_string == NULL) { 83 if (argcount != NULL) 84 *argcount = 0; 85 return (NULL); 86 } 87 88 /* 89 * set aside an initial char ** array for string array. 90 */ 91 arg_array = malloc(sizeof(char *) * max_toks); 92 93 if (arg_array == NULL) { 94 if (argcount != NULL) 95 *argcount = 0; 96 free(arg_string); 97 return (NULL); 98 } 99 100 if (separator == NULL) 101 separator = " \t"; 102 103 /* 104 * Use strtok() to parse 'arg_string', placing pointers to the 105 * individual tokens into the elements of 'arg_array'. Expand 106 * 'arg_array' if necessary. 107 */ 108 cur_tok = strtok(arg_string, separator); 109 while (cur_tok != NULL) { 110 arg_array[num_toks++] = cur_tok; 111 cur_tok = strtok(NULL, separator); 112 if (num_toks == max_toks) { 113 max_toks += 20; 114 arg_array = 115 (char **)realloc((void *)arg_array, 116 sizeof(char *) * max_toks); 117 if (arg_array == NULL) { 118 fprintf(stderr, "realloc: New memory allocation failed \n"); 119 free(arg_string); 120 exit(1); 121 } 122 } 123 } 124 arg_array[num_toks] = NULL; 125 126 /* 127 * If there are any spaces left in our array, make them NULL 128 */ 129 for (i = num_toks + 1; i < max_toks; i++) 130 arg_array[i] = NULL; 131 132 /* This seems nice, but since memory is allocated on a page basis, this 133 * isn't really helpful: 134 * arg_array = (char **)realloc((void *)arg_array, sizeof(char *)*num_toks+1 );*/ 135 136 if (argcount != NULL) 137 *argcount = num_toks; 138 139 /* 140 * Return the argument array. 141 */ 142 return ((const char **)arg_array); 143 } 144 145 /* 146 * splitster_free( const char ** ) 147 * 148 * This takes the return value from splitster() and free()s memory 149 * allocated by splitster. Assuming: ret=splitster(...), this 150 * requires that ret and *ret returned from splitster() have not 151 * been modified. 152 */ 153 void splitstr_free(const char **p_return) 154 { 155 if (*p_return != NULL) 156 free((char *)*p_return); 157 if (p_return != NULL) 158 free((char **)p_return); 159 } 160 161 #ifdef UNIT_TEST 162 163 int main() 164 { 165 int i, y, test_size = 1000, size_ret; 166 char test_str[32768]; 167 char buf[16]; 168 char *test_str_array[test_size]; 169 const char **ret; 170 171 for (i = 0; i < test_size; i++) { 172 snprintf(buf, 16, "arg%d", i); 173 test_str_array[i] = strdup(buf); 174 } 175 176 for (i = 0; i < test_size; i++) { 177 test_str[0] = '\0'; 178 for (y = 0; y < i; y++) { 179 snprintf(buf, 16, "arg%d ", y); 180 strncat(test_str, buf, 16); 181 } 182 ret = splitstr(test_str, NULL, &size_ret); 183 assert(size_ret == i); 184 for (y = 0; y < i; y++) 185 assert(strcmp(ret[y], test_str_array[y]) == 0); 186 187 splitstr_free(ret); 188 } 189 return 0; 190 } 191 192 #endif 193