1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate #include "volume_string.h" 30*0Sstevel@tonic-gate 31*0Sstevel@tonic-gate #include <ctype.h> 32*0Sstevel@tonic-gate #include <errno.h> 33*0Sstevel@tonic-gate #include <libintl.h> 34*0Sstevel@tonic-gate #include <math.h> 35*0Sstevel@tonic-gate #include <stdarg.h> 36*0Sstevel@tonic-gate #include <stdio.h> 37*0Sstevel@tonic-gate #include <stdlib.h> 38*0Sstevel@tonic-gate #include <string.h> 39*0Sstevel@tonic-gate #include "volume_error.h" 40*0Sstevel@tonic-gate #include "volume_output.h" 41*0Sstevel@tonic-gate 42*0Sstevel@tonic-gate /* 43*0Sstevel@tonic-gate * ****************************************************************** 44*0Sstevel@tonic-gate * 45*0Sstevel@tonic-gate * Function prototypes 46*0Sstevel@tonic-gate * 47*0Sstevel@tonic-gate * ****************************************************************** 48*0Sstevel@tonic-gate */ 49*0Sstevel@tonic-gate 50*0Sstevel@tonic-gate static void *append_to_pointer_array(void **array, void *pointer); 51*0Sstevel@tonic-gate 52*0Sstevel@tonic-gate /* 53*0Sstevel@tonic-gate * ****************************************************************** 54*0Sstevel@tonic-gate * 55*0Sstevel@tonic-gate * Data 56*0Sstevel@tonic-gate * 57*0Sstevel@tonic-gate * ****************************************************************** 58*0Sstevel@tonic-gate */ 59*0Sstevel@tonic-gate 60*0Sstevel@tonic-gate /* All-inclusive valid size units */ 61*0Sstevel@tonic-gate units_t universal_units[] = { 62*0Sstevel@tonic-gate {"BLOCKS", BYTES_PER_BLOCK}, 63*0Sstevel@tonic-gate {"KB", BYTES_PER_KILOBYTE}, 64*0Sstevel@tonic-gate {"MB", BYTES_PER_MEGABYTE}, 65*0Sstevel@tonic-gate {"GB", BYTES_PER_GIGABYTE}, 66*0Sstevel@tonic-gate {"TB", BYTES_PER_TERABYTE}, 67*0Sstevel@tonic-gate {NULL, 0} 68*0Sstevel@tonic-gate }; 69*0Sstevel@tonic-gate 70*0Sstevel@tonic-gate /* 71*0Sstevel@tonic-gate * ****************************************************************** 72*0Sstevel@tonic-gate * 73*0Sstevel@tonic-gate * External functions 74*0Sstevel@tonic-gate * 75*0Sstevel@tonic-gate * ****************************************************************** 76*0Sstevel@tonic-gate */ 77*0Sstevel@tonic-gate 78*0Sstevel@tonic-gate /* 79*0Sstevel@tonic-gate * Concatenates a list of strings. The result must be free()d. 80*0Sstevel@tonic-gate * 81*0Sstevel@tonic-gate * @param numargs 82*0Sstevel@tonic-gate * The number of strings to concatenate. 83*0Sstevel@tonic-gate * 84*0Sstevel@tonic-gate * @param ... 85*0Sstevel@tonic-gate * The strings (type char *) to concatenate. 86*0Sstevel@tonic-gate * 87*0Sstevel@tonic-gate * @return the concatenated string 88*0Sstevel@tonic-gate * if succesful 89*0Sstevel@tonic-gate * 90*0Sstevel@tonic-gate * @return NULL 91*0Sstevel@tonic-gate * if memory could not be allocated 92*0Sstevel@tonic-gate */ 93*0Sstevel@tonic-gate char * 94*0Sstevel@tonic-gate stralloccat( 95*0Sstevel@tonic-gate int numargs, 96*0Sstevel@tonic-gate ...) 97*0Sstevel@tonic-gate { 98*0Sstevel@tonic-gate va_list vl; 99*0Sstevel@tonic-gate int i; 100*0Sstevel@tonic-gate int len = 1; 101*0Sstevel@tonic-gate char *cat; 102*0Sstevel@tonic-gate 103*0Sstevel@tonic-gate /* Determine length of concatenated string */ 104*0Sstevel@tonic-gate va_start(vl, numargs); 105*0Sstevel@tonic-gate for (i = 0; i < numargs; i++) { 106*0Sstevel@tonic-gate char *str = va_arg(vl, char *); 107*0Sstevel@tonic-gate if (str != NULL) { 108*0Sstevel@tonic-gate len += strlen(str); 109*0Sstevel@tonic-gate } 110*0Sstevel@tonic-gate } 111*0Sstevel@tonic-gate va_end(vl); 112*0Sstevel@tonic-gate 113*0Sstevel@tonic-gate /* Allocate memory for concatenation plus a trailing NULL */ 114*0Sstevel@tonic-gate cat = (char *)calloc(1, len * sizeof (char)); 115*0Sstevel@tonic-gate 116*0Sstevel@tonic-gate if (cat == NULL) { 117*0Sstevel@tonic-gate return (NULL); 118*0Sstevel@tonic-gate } 119*0Sstevel@tonic-gate 120*0Sstevel@tonic-gate /* Concatenate strings */ 121*0Sstevel@tonic-gate va_start(vl, numargs); 122*0Sstevel@tonic-gate for (i = 0; i < numargs; i++) { 123*0Sstevel@tonic-gate char *str = va_arg(vl, char *); 124*0Sstevel@tonic-gate if (str != NULL) { 125*0Sstevel@tonic-gate strcat(cat, str); 126*0Sstevel@tonic-gate } 127*0Sstevel@tonic-gate } 128*0Sstevel@tonic-gate va_end(vl); 129*0Sstevel@tonic-gate 130*0Sstevel@tonic-gate return (cat); 131*0Sstevel@tonic-gate } 132*0Sstevel@tonic-gate 133*0Sstevel@tonic-gate /* 134*0Sstevel@tonic-gate * Convert the given string to a uint16_t, verifying that the value 135*0Sstevel@tonic-gate * does not exceed the lower or upper bounds of a uint16_t. 136*0Sstevel@tonic-gate * 137*0Sstevel@tonic-gate * @param str 138*0Sstevel@tonic-gate * the string to convert 139*0Sstevel@tonic-gate * 140*0Sstevel@tonic-gate * @param num 141*0Sstevel@tonic-gate * the addr of the uint16_t 142*0Sstevel@tonic-gate * 143*0Sstevel@tonic-gate * @return 0 144*0Sstevel@tonic-gate * if the given string was converted to a uint16_t 145*0Sstevel@tonic-gate * 146*0Sstevel@tonic-gate * @return -1 147*0Sstevel@tonic-gate * if the string could could not be converted to a number 148*0Sstevel@tonic-gate * 149*0Sstevel@tonic-gate * @return -2 150*0Sstevel@tonic-gate * if the converted number exceeds the lower or upper 151*0Sstevel@tonic-gate * bounds of a uint16_t 152*0Sstevel@tonic-gate */ 153*0Sstevel@tonic-gate int 154*0Sstevel@tonic-gate str_to_uint16( 155*0Sstevel@tonic-gate char *str, 156*0Sstevel@tonic-gate uint16_t *num) 157*0Sstevel@tonic-gate { 158*0Sstevel@tonic-gate long long lnum; 159*0Sstevel@tonic-gate int error = 0; 160*0Sstevel@tonic-gate 161*0Sstevel@tonic-gate /* Convert string to long long */ 162*0Sstevel@tonic-gate if (sscanf(str, "%lld", &lnum) != 1) { 163*0Sstevel@tonic-gate error = -1; 164*0Sstevel@tonic-gate } else { 165*0Sstevel@tonic-gate 166*0Sstevel@tonic-gate /* 167*0Sstevel@tonic-gate * Verify that the long long value does not exceed the 168*0Sstevel@tonic-gate * lower or upper bounds of a uint16_t 169*0Sstevel@tonic-gate */ 170*0Sstevel@tonic-gate 171*0Sstevel@tonic-gate /* Maximum value of uint16_t */ 172*0Sstevel@tonic-gate uint16_t max = (uint16_t)~0ULL; 173*0Sstevel@tonic-gate 174*0Sstevel@tonic-gate if (lnum < 0 || lnum > max) { 175*0Sstevel@tonic-gate error = -2; 176*0Sstevel@tonic-gate } else { 177*0Sstevel@tonic-gate *num = lnum; 178*0Sstevel@tonic-gate } 179*0Sstevel@tonic-gate } 180*0Sstevel@tonic-gate 181*0Sstevel@tonic-gate return (error); 182*0Sstevel@tonic-gate } 183*0Sstevel@tonic-gate 184*0Sstevel@tonic-gate /* 185*0Sstevel@tonic-gate * Converts the given long long into a string. This string must be 186*0Sstevel@tonic-gate * freed. 187*0Sstevel@tonic-gate * 188*0Sstevel@tonic-gate * @param num 189*0Sstevel@tonic-gate * the long long to convert 190*0Sstevel@tonic-gate * 191*0Sstevel@tonic-gate * @param str 192*0Sstevel@tonic-gate * the addr of the string 193*0Sstevel@tonic-gate * 194*0Sstevel@tonic-gate * @return 0 195*0Sstevel@tonic-gate * if successful 196*0Sstevel@tonic-gate * 197*0Sstevel@tonic-gate * @return ENOMEM 198*0Sstevel@tonic-gate * if the physical limits of the system are exceeded by 199*0Sstevel@tonic-gate * size bytes of memory which cannot be allocated 200*0Sstevel@tonic-gate * 201*0Sstevel@tonic-gate * @return EAGAIN 202*0Sstevel@tonic-gate * if there is not enough memory available to allocate 203*0Sstevel@tonic-gate * size bytes of memory 204*0Sstevel@tonic-gate */ 205*0Sstevel@tonic-gate int 206*0Sstevel@tonic-gate ll_to_str( 207*0Sstevel@tonic-gate long long num, 208*0Sstevel@tonic-gate char **str) 209*0Sstevel@tonic-gate { 210*0Sstevel@tonic-gate int error = 0; 211*0Sstevel@tonic-gate 212*0Sstevel@tonic-gate /* Allocate memory for the string */ 213*0Sstevel@tonic-gate if ((*str = calloc(1, LONG_LONG_STR_SIZE * sizeof (char))) == NULL) { 214*0Sstevel@tonic-gate error = errno; 215*0Sstevel@tonic-gate } else { 216*0Sstevel@tonic-gate /* Convert the integer to a string */ 217*0Sstevel@tonic-gate snprintf(*str, LONG_LONG_STR_SIZE, "%lld", num); 218*0Sstevel@tonic-gate } 219*0Sstevel@tonic-gate 220*0Sstevel@tonic-gate return (error); 221*0Sstevel@tonic-gate } 222*0Sstevel@tonic-gate 223*0Sstevel@tonic-gate /* 224*0Sstevel@tonic-gate * Convert a size specification to bytes. 225*0Sstevel@tonic-gate * 226*0Sstevel@tonic-gate * @param str 227*0Sstevel@tonic-gate * a size specification strings of the form 228*0Sstevel@tonic-gate * <value><units>, where valid <units> are specified by 229*0Sstevel@tonic-gate * the units argument and <value> is the (floating-point) 230*0Sstevel@tonic-gate * multiplier of the units 231*0Sstevel@tonic-gate * 232*0Sstevel@tonic-gate * @param bytes 233*0Sstevel@tonic-gate * RETURN: the result of converting the given size string 234*0Sstevel@tonic-gate * to bytes 235*0Sstevel@tonic-gate * 236*0Sstevel@tonic-gate * @return 0 237*0Sstevel@tonic-gate * if successful 238*0Sstevel@tonic-gate * 239*0Sstevel@tonic-gate * @return non-zero 240*0Sstevel@tonic-gate * if an error occurred. Use get_error_string() to 241*0Sstevel@tonic-gate * retrieve the associated error message. 242*0Sstevel@tonic-gate */ 243*0Sstevel@tonic-gate int 244*0Sstevel@tonic-gate sizestr_to_bytes( 245*0Sstevel@tonic-gate char *str, 246*0Sstevel@tonic-gate uint64_t *bytes, 247*0Sstevel@tonic-gate units_t units[]) 248*0Sstevel@tonic-gate { 249*0Sstevel@tonic-gate char *unit_str; 250*0Sstevel@tonic-gate long double d; 251*0Sstevel@tonic-gate int error = 0; 252*0Sstevel@tonic-gate int i; 253*0Sstevel@tonic-gate 254*0Sstevel@tonic-gate /* Convert <value> string to double */ 255*0Sstevel@tonic-gate if ((d = strtod(str, &unit_str)) == 0) { 256*0Sstevel@tonic-gate volume_set_error(gettext("invalid size string: %s"), str); 257*0Sstevel@tonic-gate error = -1; 258*0Sstevel@tonic-gate } else { 259*0Sstevel@tonic-gate 260*0Sstevel@tonic-gate /* Trim leading white space */ 261*0Sstevel@tonic-gate while (isspace(*unit_str) != 0) { 262*0Sstevel@tonic-gate ++unit_str; 263*0Sstevel@tonic-gate } 264*0Sstevel@tonic-gate 265*0Sstevel@tonic-gate /* Convert to bytes based on <units> */ 266*0Sstevel@tonic-gate for (i = 0; units[i].unit_str != NULL; i++) { 267*0Sstevel@tonic-gate if (strcasecmp(unit_str, units[i].unit_str) == 0) { 268*0Sstevel@tonic-gate d *= units[i].bytes_per_unit; 269*0Sstevel@tonic-gate break; 270*0Sstevel@tonic-gate } 271*0Sstevel@tonic-gate } 272*0Sstevel@tonic-gate 273*0Sstevel@tonic-gate /* Was a valid unit string found? */ 274*0Sstevel@tonic-gate if (units[i].unit_str == NULL) { 275*0Sstevel@tonic-gate volume_set_error( 276*0Sstevel@tonic-gate gettext("missing or invalid units indicator in size: %s"), 277*0Sstevel@tonic-gate str); 278*0Sstevel@tonic-gate error = -1; 279*0Sstevel@tonic-gate } 280*0Sstevel@tonic-gate } 281*0Sstevel@tonic-gate 282*0Sstevel@tonic-gate if (error) { 283*0Sstevel@tonic-gate *bytes = 0; 284*0Sstevel@tonic-gate } else { 285*0Sstevel@tonic-gate *bytes = (uint64_t)d; 286*0Sstevel@tonic-gate oprintf(OUTPUT_DEBUG, 287*0Sstevel@tonic-gate gettext("converted \"%s\" to %llu bytes\n"), str, *bytes); 288*0Sstevel@tonic-gate } 289*0Sstevel@tonic-gate 290*0Sstevel@tonic-gate return (error); 291*0Sstevel@tonic-gate } 292*0Sstevel@tonic-gate 293*0Sstevel@tonic-gate /* 294*0Sstevel@tonic-gate * Convert bytes to a size specification string. 295*0Sstevel@tonic-gate * 296*0Sstevel@tonic-gate * @param bytes 297*0Sstevel@tonic-gate * the number of bytes 298*0Sstevel@tonic-gate * 299*0Sstevel@tonic-gate * @param str 300*0Sstevel@tonic-gate * RETURN: a size specification strings of the form 301*0Sstevel@tonic-gate * <value><units>, where valid <units> are specified by 302*0Sstevel@tonic-gate * the units argument and <value> is the (floating-point) 303*0Sstevel@tonic-gate * multiplier of the units. This string must be freed. 304*0Sstevel@tonic-gate * 305*0Sstevel@tonic-gate * @return 0 306*0Sstevel@tonic-gate * if successful 307*0Sstevel@tonic-gate * 308*0Sstevel@tonic-gate * @return non-zero 309*0Sstevel@tonic-gate * if an error occurred. Use get_error_string() to 310*0Sstevel@tonic-gate * retrieve the associated error message. 311*0Sstevel@tonic-gate */ 312*0Sstevel@tonic-gate int 313*0Sstevel@tonic-gate bytes_to_sizestr( 314*0Sstevel@tonic-gate uint64_t bytes, 315*0Sstevel@tonic-gate char **str, 316*0Sstevel@tonic-gate units_t units[], 317*0Sstevel@tonic-gate boolean_t round) 318*0Sstevel@tonic-gate { 319*0Sstevel@tonic-gate int i, len, error = 0; 320*0Sstevel@tonic-gate double value; 321*0Sstevel@tonic-gate const char *format; 322*0Sstevel@tonic-gate units_t use_units = units[0]; 323*0Sstevel@tonic-gate 324*0Sstevel@tonic-gate /* Determine the units to use */ 325*0Sstevel@tonic-gate for (i = 0; units[i].unit_str != NULL; i++) { 326*0Sstevel@tonic-gate if (bytes >= units[i].bytes_per_unit) { 327*0Sstevel@tonic-gate use_units = units[i]; 328*0Sstevel@tonic-gate } 329*0Sstevel@tonic-gate } 330*0Sstevel@tonic-gate 331*0Sstevel@tonic-gate value = ((long double)bytes / use_units.bytes_per_unit); 332*0Sstevel@tonic-gate 333*0Sstevel@tonic-gate /* Length of string plus trailing NULL */ 334*0Sstevel@tonic-gate len = LONG_LONG_STR_SIZE + strlen(use_units.unit_str) + 1; 335*0Sstevel@tonic-gate 336*0Sstevel@tonic-gate if (round) { 337*0Sstevel@tonic-gate value = floor(value + 0.5F); 338*0Sstevel@tonic-gate format = "%.0f%s"; 339*0Sstevel@tonic-gate } else { 340*0Sstevel@tonic-gate format = "%.2f%s"; 341*0Sstevel@tonic-gate } 342*0Sstevel@tonic-gate 343*0Sstevel@tonic-gate /* Append units to string */ 344*0Sstevel@tonic-gate *str = calloc(1, len * sizeof (char)); 345*0Sstevel@tonic-gate if (*str == NULL) { 346*0Sstevel@tonic-gate error = errno; 347*0Sstevel@tonic-gate } else { 348*0Sstevel@tonic-gate snprintf(*str, len, format, value, use_units.unit_str); 349*0Sstevel@tonic-gate } 350*0Sstevel@tonic-gate 351*0Sstevel@tonic-gate return (error); 352*0Sstevel@tonic-gate } 353*0Sstevel@tonic-gate 354*0Sstevel@tonic-gate /* 355*0Sstevel@tonic-gate * Appends a copy of the given string to the given string array, 356*0Sstevel@tonic-gate * ensuring that the last element in the array is NULL. This array 357*0Sstevel@tonic-gate * must be freed via free_string_array. 358*0Sstevel@tonic-gate * 359*0Sstevel@tonic-gate * Note when an error occurs and NULL is returned, array is not freed. 360*0Sstevel@tonic-gate * Subsequently callers should save a pointer to the original array 361*0Sstevel@tonic-gate * until success is verified. 362*0Sstevel@tonic-gate * 363*0Sstevel@tonic-gate * @param array 364*0Sstevel@tonic-gate * the array to append to, or NULL to create a new array 365*0Sstevel@tonic-gate * 366*0Sstevel@tonic-gate * @param str 367*0Sstevel@tonic-gate * the string to copy and add to the array 368*0Sstevel@tonic-gate * 369*0Sstevel@tonic-gate * @return a pointer to the realloc'd (and possibly moved) array 370*0Sstevel@tonic-gate * if succesful 371*0Sstevel@tonic-gate * 372*0Sstevel@tonic-gate * @return NULL 373*0Sstevel@tonic-gate * if unsuccesful 374*0Sstevel@tonic-gate */ 375*0Sstevel@tonic-gate char ** 376*0Sstevel@tonic-gate append_to_string_array( 377*0Sstevel@tonic-gate char **array, 378*0Sstevel@tonic-gate char *str) 379*0Sstevel@tonic-gate { 380*0Sstevel@tonic-gate char *copy = strdup(str); 381*0Sstevel@tonic-gate 382*0Sstevel@tonic-gate if (copy == NULL) { 383*0Sstevel@tonic-gate return (NULL); 384*0Sstevel@tonic-gate } 385*0Sstevel@tonic-gate 386*0Sstevel@tonic-gate return ((char **)append_to_pointer_array((void **)array, copy)); 387*0Sstevel@tonic-gate } 388*0Sstevel@tonic-gate 389*0Sstevel@tonic-gate /* 390*0Sstevel@tonic-gate * Frees each element of the given string array, then frees the array 391*0Sstevel@tonic-gate * itself. 392*0Sstevel@tonic-gate * 393*0Sstevel@tonic-gate * @param array 394*0Sstevel@tonic-gate * a NULL-terminated string array 395*0Sstevel@tonic-gate */ 396*0Sstevel@tonic-gate void 397*0Sstevel@tonic-gate free_string_array( 398*0Sstevel@tonic-gate char **array) 399*0Sstevel@tonic-gate { 400*0Sstevel@tonic-gate int i; 401*0Sstevel@tonic-gate 402*0Sstevel@tonic-gate /* Free each available element */ 403*0Sstevel@tonic-gate for (i = 0; array[i] != NULL; i++) { 404*0Sstevel@tonic-gate free(array[i]); 405*0Sstevel@tonic-gate } 406*0Sstevel@tonic-gate 407*0Sstevel@tonic-gate /* Free the array itself */ 408*0Sstevel@tonic-gate free((void *)array); 409*0Sstevel@tonic-gate } 410*0Sstevel@tonic-gate 411*0Sstevel@tonic-gate /* 412*0Sstevel@tonic-gate * ****************************************************************** 413*0Sstevel@tonic-gate * 414*0Sstevel@tonic-gate * Static functions 415*0Sstevel@tonic-gate * 416*0Sstevel@tonic-gate * ****************************************************************** 417*0Sstevel@tonic-gate */ 418*0Sstevel@tonic-gate 419*0Sstevel@tonic-gate /* 420*0Sstevel@tonic-gate * Appends the given pointer to the given pointer array, ensuring that 421*0Sstevel@tonic-gate * the last element in the array is NULL. 422*0Sstevel@tonic-gate * 423*0Sstevel@tonic-gate * Note when an error occurs and NULL is returned, array is not freed. 424*0Sstevel@tonic-gate * Subsequently callers should save a pointer to the original array 425*0Sstevel@tonic-gate * until success is verified. 426*0Sstevel@tonic-gate * 427*0Sstevel@tonic-gate * @param array 428*0Sstevel@tonic-gate * the array to append to, or NULL to create a new array 429*0Sstevel@tonic-gate * 430*0Sstevel@tonic-gate * @param pointer 431*0Sstevel@tonic-gate * the pointer to add to the array 432*0Sstevel@tonic-gate * 433*0Sstevel@tonic-gate * @return a pointer to the realloc'd (and possibly moved) array 434*0Sstevel@tonic-gate * if succesful 435*0Sstevel@tonic-gate * 436*0Sstevel@tonic-gate * @return NULL 437*0Sstevel@tonic-gate * if unsuccesful 438*0Sstevel@tonic-gate */ 439*0Sstevel@tonic-gate static void * 440*0Sstevel@tonic-gate append_to_pointer_array( 441*0Sstevel@tonic-gate void **array, 442*0Sstevel@tonic-gate void *pointer) 443*0Sstevel@tonic-gate { 444*0Sstevel@tonic-gate void **newarray = NULL; 445*0Sstevel@tonic-gate int i = 0; 446*0Sstevel@tonic-gate 447*0Sstevel@tonic-gate if (array != NULL) { 448*0Sstevel@tonic-gate /* Count the elements currently in the array */ 449*0Sstevel@tonic-gate for (i = 0; array[i] != NULL; ++i); 450*0Sstevel@tonic-gate } 451*0Sstevel@tonic-gate 452*0Sstevel@tonic-gate /* realloc, adding a slot for the new pointer */ 453*0Sstevel@tonic-gate newarray = (void **)realloc(array, (i + 2) * sizeof (*array)); 454*0Sstevel@tonic-gate 455*0Sstevel@tonic-gate if (newarray != NULL) { 456*0Sstevel@tonic-gate /* Append pointer and terminal NULL */ 457*0Sstevel@tonic-gate newarray[i] = pointer; 458*0Sstevel@tonic-gate newarray[i+1] = NULL; 459*0Sstevel@tonic-gate } 460*0Sstevel@tonic-gate 461*0Sstevel@tonic-gate return (newarray); 462*0Sstevel@tonic-gate } 463