vls.c

Go to the documentation of this file.
00001 /*                           V L S . C
00002  * BRL-CAD
00003  *
00004  * Copyright (c) 2004-2006 United States Government as represented by
00005  * the U.S. Army Research Laboratory.
00006  *
00007  * This library is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU Lesser General Public License
00009  * as published by the Free Software Foundation; either version 2 of
00010  * the License, or (at your option) any later version.
00011  *
00012  * This library is distributed in the hope that it will be useful, but
00013  * WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  * Library General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU Lesser General Public
00018  * License along with this file; see the file named COPYING for more
00019  * information.
00020  */
00021 
00022 /** \addtogroup vls */
00023 /*@{*/
00024 /** @file vls.c
00025  *
00026  *  @brief The variable length string package.
00027  *
00028  *  The variable length string package.
00029  *
00030  *  Assumption:  libc-provided sprintf() function is safe to use in parallel,
00031  *  on parallel systems.
00032  *
00033  *  @author
00034  *      Michael John Muuss
00035  *
00036  *  @par Source -
00037  *      SECAD/VLD Computing Consortium, Bldg 394
00038  *@n    The U. S. Army Ballistic Research Laboratory
00039  *@n    Aberdeen Proving Ground, Maryland  21005-5066
00040  *
00041  */
00042 
00043 static const char libbu_vls_RCSid[] = "@(#)$Header: /cvsroot/brlcad/brlcad/src/libbu/vls.c,v 14.20 2006/09/03 15:14:07 lbutler Exp $ (BRL)";
00044 
00045 #include "common.h"
00046 
00047 #include <stdlib.h>
00048 #include <stdio.h>
00049 #include <ctype.h>
00050 #ifdef HAVE_STRING_H
00051 #  include <string.h>
00052 #else
00053 #  include <strings.h>
00054 #endif
00055 #if defined(HAVE_STDARG_H)
00056 /* ANSI C */
00057 #  include <stdarg.h>
00058 #endif
00059 #if !defined(HAVE_STDARG_H) && defined(HAVE_VARARGS_H)
00060 /* VARARGS */
00061 #  include <varargs.h>
00062 #endif
00063 #ifdef HAVE_UNISTD_H
00064 #  include <unistd.h>
00065 #endif
00066 
00067 #include "machine.h"
00068 #include "bu.h"
00069 
00070 #if defined(HAVE_VARARGS_H) || defined(HAVE_STDARG_H)
00071 BU_EXTERN(void  bu_vls_vprintf, (struct bu_vls *vls, const char *fmt, va_list ap));
00072 #endif
00073 
00074 const char bu_vls_message[] = "bu_vls_str";
00075 extern const char bu_strdup_message[];
00076 
00077 /**
00078  *                      B U _ V L S _ I N I T
00079  *
00080  *  No storage should be allocated at this point,
00081  *  and bu_vls_addr() must be able to live with that.
00082  */
00083 void
00084 bu_vls_init(register struct bu_vls *vp)
00085 {
00086     if (vp == (struct bu_vls  *)NULL)
00087         bu_bomb("bu_vls_init() passed NULL pointer");
00088 
00089     /* if it's already a vls, perform a sanity check that we're not
00090      * leaking memory.
00091      */
00092 #if defined(DEBUG) && 0
00093     if (vp->vls_magic == BU_VLS_MAGIC) {
00094         if (vp->vls_str && vp->vls_len > 0 && vp->vls_max > 0) {
00095             bu_log("bu_vls_init potential leak [%s] (vls_len=%d)\n", vp->vls_str, vp->vls_len);
00096         }
00097     }
00098 #endif
00099     vp->vls_magic = BU_VLS_MAGIC;
00100     vp->vls_str = (char *)0;
00101     vp->vls_len = vp->vls_max = vp->vls_offset = 0;
00102 }
00103 
00104 /**
00105  *                      B U _ V L S _ I N I T _ I F _ U N I N I T
00106  *
00107  *  If a VLS is unitialized, initialize it.
00108  *  If it is already initialized, leave it alone, caller wants to
00109  *  append to it.
00110  */
00111 void
00112 bu_vls_init_if_uninit(register struct bu_vls *vp)
00113 {
00114     if (vp == (struct bu_vls  *)NULL)
00115         bu_bomb("bu_vls_init_if_uninit() passed NULL pointer");
00116 
00117     if( vp->vls_magic == BU_VLS_MAGIC )  return;
00118     bu_vls_init( vp );
00119 }
00120 
00121 
00122 /**
00123  *                      B U _ V L S _ V L S I N I T
00124  *
00125  *  Allocate storage for a struct bu_vls, call bu_vls_init on it, and return
00126  *  the result.  Allows for creation of dynamically allocated vls strings.
00127  */
00128 struct bu_vls *
00129 bu_vls_vlsinit(void)
00130 {
00131     register struct bu_vls      *vp;
00132 
00133     vp = (struct bu_vls *)bu_malloc(sizeof(struct bu_vls), "bu_vls_vlsinit struct");
00134     bu_vls_init(vp);
00135 
00136     return vp;
00137 }
00138 
00139 /**
00140  *                      B U _ V L S _ A D D R
00141  *
00142  *  Return a pointer to the null-terminated string in the vls array.
00143  *  If no storage has been allocated yet, give back a valid string.
00144  */
00145 char *
00146 bu_vls_addr(register const struct bu_vls *vp)
00147 {
00148     static char nullbuf[4];
00149 
00150     BU_CK_VLS(vp);
00151 
00152     if( vp->vls_max == 0 || vp->vls_str == (char *)NULL )  {
00153         /* A zero-length VLS is a null string */
00154         nullbuf[0] = '\0';
00155         return(nullbuf);
00156     }
00157 
00158     /* Sanity checking */
00159     if( vp->vls_max < 0 ||
00160         vp->vls_len < 0 ||
00161         vp->vls_offset < 0 ||
00162         vp->vls_str == (char *)NULL ||
00163         vp->vls_len + vp->vls_offset >= vp->vls_max )  {
00164         bu_log("bu_vls_addr: bad VLS.  max=%d, len=%d, offset=%d\n",
00165                vp->vls_max, vp->vls_len, vp->vls_offset);
00166         bu_bomb("bu_vls_addr\n");
00167     }
00168 
00169     return( vp->vls_str+vp->vls_offset );
00170 }
00171 
00172 /**
00173  *                      B U _ V L S _ E X T E N D
00174  */
00175 void
00176 bu_vls_extend(register struct bu_vls *vp, unsigned int extra)
00177 {
00178     BU_CK_VLS(vp);
00179     if( extra < 40 )  extra = 40;
00180     if( vp->vls_max <= 0 || vp->vls_str == (char *)0 )  {
00181         vp->vls_max = extra;
00182         vp->vls_str = (char *)bu_malloc( vp->vls_max, bu_vls_message );
00183         vp->vls_len = 0;
00184         vp->vls_offset = 0;
00185         *vp->vls_str = '\0';
00186         return;
00187     }
00188     if( vp->vls_offset + vp->vls_len + extra >= vp->vls_max )  {
00189         vp->vls_max += extra;
00190         if( vp->vls_max < 120 )  vp->vls_max = 120;
00191         vp->vls_str = (char *)bu_realloc( vp->vls_str, vp->vls_max,
00192                                           bu_vls_message );
00193     }
00194 }
00195 
00196 /**
00197  *                      B U _ V L S _ S E T L E N
00198  *
00199  *  Ensure that the vls has a length of at least 'newlen', and make
00200  *  that the current length.
00201  *  Useful for subroutines that are planning on mucking with the data
00202  *  array themselves.  Not advisable, but occasionally useful.
00203  *  Does not change the offset from the front of the buffer, if any.
00204  *  Does not initialize the value of any of the new bytes.
00205  */
00206 void
00207 bu_vls_setlen(struct bu_vls *vp, int newlen)
00208 {
00209     BU_CK_VLS(vp);
00210     if( vp->vls_len >= newlen )  return;
00211     bu_vls_extend( vp, newlen - vp->vls_len );
00212     vp->vls_len = newlen;
00213 }
00214 
00215 /**
00216  *                      B U _ V L S _ S T R L E N
00217  *
00218  *  Return length of the string, in bytes, not including the null terminator.
00219  */
00220 int
00221 bu_vls_strlen(register const struct bu_vls *vp)
00222 {
00223     BU_CK_VLS(vp);
00224     if( vp->vls_len <= 0 )  return  0;
00225     return  vp->vls_len;
00226 }
00227 
00228 /**
00229  *                      B U _ V L S _ T R U N C
00230  *
00231  *  Truncate string to at most 'len' characters.
00232  *  If 'len' is negative, trim off that many from the end.
00233  *  If 'len' is zero, don't release storage -- user is probably
00234  *  just going to refill it again, e.g. with bu_vls_gets().
00235  */
00236 void
00237 bu_vls_trunc(register struct bu_vls *vp, int len)
00238 {
00239     BU_CK_VLS(vp);
00240     if( len < 0 )  len = vp->vls_len + len;     /* now an absolute length */
00241     if( vp->vls_len <= len )  return;
00242     if( len == 0 )  vp->vls_offset = 0;
00243     vp->vls_str[len+vp->vls_offset] = '\0';     /* force null termination */
00244     vp->vls_len = len;
00245 }
00246 
00247 /**
00248  *                      B U _ V L S _ T R U N C 2
00249  *
00250  *  Son of bu_vls_trunc.
00251  *  Same as bu_vls_trunc except that it doesn't take negative len.
00252  */
00253 void
00254 bu_vls_trunc2(register struct bu_vls *vp, int len)
00255 {
00256     BU_CK_VLS(vp);
00257     if( vp->vls_len <= len )  return;
00258     if( len < 0 )  len = 0;
00259     if( len == 0 )  vp->vls_offset = 0;
00260     vp->vls_str[len+vp->vls_offset] = '\0';     /* force null termination */
00261     vp->vls_len = len;
00262 }
00263 
00264 /**
00265  *                      B U _ V L S _ N I B B L E
00266  *
00267  *  "Nibble" 'len' characters off the front of the string.
00268  *  Changes the length and offset;  no data is copied.
00269  *  'len' may be positive or negative.
00270  *  If negative, characters are un-nibbled.
00271  */
00272 void
00273 bu_vls_nibble(register struct bu_vls *vp, int len)
00274 {
00275     BU_CK_VLS(vp);
00276     if( len < 0 && (-len) > vp->vls_offset )  len = -vp->vls_offset;
00277     if (len >= vp->vls_len) {
00278         bu_vls_trunc( vp, 0 );
00279         return;
00280     }
00281     vp->vls_len -= len;
00282     vp->vls_offset += len;
00283 }
00284 
00285 /**
00286  *                      B U _ V L S _ F R E E
00287  *
00288  *  Releases the memory used for the string buffer.
00289  */
00290 void
00291 bu_vls_free(register struct bu_vls *vp)
00292 {
00293     BU_CK_VLS(vp);
00294     if( vp->vls_str )  {
00295         vp->vls_str[0] = '?';           /* Sanity */
00296         bu_free( vp->vls_str, "bu_vls_free" );
00297         vp->vls_str = (char *)0;
00298     }
00299     vp->vls_offset = vp->vls_len = vp->vls_max = 0;
00300 }
00301 
00302 /**
00303  *                      B U _ V L S _ V L S F R E E
00304  *
00305  *  Releases the memory used for the string buffer and the memory for
00306  *  the vls structure
00307  */
00308 void
00309 bu_vls_vlsfree(register struct bu_vls *vp)
00310 {
00311     if ( *(long *)vp != BU_VLS_MAGIC) return;
00312 
00313     bu_vls_free( vp );
00314     bu_free( vp, "bu_vls_vlsfree" );
00315 }
00316 
00317 /**
00318  *                      B U _ V L S _ S T R D U P
00319  *
00320  *  Make an "ordinary" string copy of a vls string.  Storage for the regular
00321  *  string is acquired using malloc.
00322  *  The source string is not affected.
00323  */
00324 char *
00325 bu_vls_strdup(register const struct bu_vls *vp)
00326 {
00327     register char *str;
00328     register int len;
00329 
00330     len = bu_vls_strlen(vp);
00331     str = bu_malloc(len+1, bu_strdup_message );
00332     strncpy(str, bu_vls_addr(vp), len);
00333     str[len] = '\0';
00334     return str;
00335 }
00336 
00337 /**
00338  *                      B U _ V L S _ S T R G R A B
00339  *
00340  *  Like bu_vls_strdup(), but destructively grab the string from the
00341  *  source argument 'vp'.  This is more efficient than bu_vls_strdup() for
00342  *  those instances where the source argument 'vp' is no longer needed
00343  *  by the caller, as it avoides a potentially long buffer copy.
00344  *
00345  *  The source string is destroyed, as if bu_vls_free() had been called.
00346  */
00347 char *
00348 bu_vls_strgrab(register struct bu_vls *vp)
00349 {
00350     register char *str;
00351 
00352     BU_CK_VLS(vp);
00353     if( vp->vls_offset != 0 )  {
00354         str = bu_vls_strdup( vp );
00355         bu_vls_free( vp );
00356         return str;
00357     }
00358 
00359     str = bu_vls_addr( vp );
00360     vp->vls_str = (char *)0;
00361     vp->vls_offset = vp->vls_len = vp->vls_max = 0;
00362     return str;
00363 }
00364 
00365 /**
00366  *                      B U _ V L S _ S T R C P Y
00367  *
00368  *  Empty the vls string, and copy in a regular string.
00369  */
00370 void
00371 bu_vls_strcpy(register struct bu_vls *vp, const char *s)
00372 {
00373     register int        len;
00374 
00375     BU_CK_VLS(vp);
00376     if( s == (const char *)NULL )  return;
00377     if( (len = strlen(s)) <= 0 )  {
00378         vp->vls_len = 0;
00379         vp->vls_offset = 0;
00380         if(vp->vls_max > 0)
00381             vp->vls_str[0] = '\0';
00382         return;
00383     }
00384     vp->vls_offset = 0;         /* cancel offset before extending */
00385     if( len+1 >= vp->vls_max )  bu_vls_extend( vp, len+1 );
00386     bcopy( s, vp->vls_str, len+1 );             /* include null */
00387     vp->vls_len = len;
00388 }
00389 
00390 /**
00391  *                      B U _ V L S _ S T R N C P Y
00392  *
00393  *  Empty the vls string, and copy in a regular string, up to N bytes long.
00394  */
00395 void
00396 bu_vls_strncpy(register struct bu_vls *vp, const char *s, long int n)
00397 {
00398     register int        len;
00399 
00400     BU_CK_VLS(vp);
00401     if( s == (const char *)NULL )  return;
00402     len = strlen(s);
00403     if( len > n )  len = n;
00404     if( len <= 0 )  {
00405         vp->vls_len = 0;        /* ensure string is empty */
00406         return;
00407     }
00408     vp->vls_offset = 0;         /* cancel offset before extending */
00409     if( len+1 >= vp->vls_max )  bu_vls_extend( vp, len+1 );
00410     bcopy( s, vp->vls_str, len );
00411     vp->vls_str[len] = '\0';            /* force null termination */
00412     vp->vls_len = len;
00413 }
00414 
00415 /**
00416  *                      B U _ V L S _ S T R C A T
00417  *
00418  *  Concatenate a new string onto the end of the existing vls string.
00419  */
00420 void
00421 bu_vls_strcat(register struct bu_vls *vp, const char *s)
00422 {
00423     register int        len;
00424 
00425     BU_CK_VLS(vp);
00426     if( s == (const char *)NULL )  return;
00427     if( (len = strlen(s)) <= 0 )  return;
00428     if( vp->vls_offset + vp->vls_len + len+1 >= vp->vls_max )
00429         bu_vls_extend( vp, len+1 );
00430     bcopy( s, vp->vls_str +vp->vls_offset + vp->vls_len, len+1 );       /* include null */
00431     vp->vls_len += len;
00432 }
00433 
00434 /**
00435  *                      B U _ V L S _ S T R N C A T
00436  *
00437  *  Concatenate a new string onto the end of the existing vls string.
00438  */
00439 void
00440 bu_vls_strncat(register struct bu_vls *vp, const char *s, long int n)
00441 {
00442     register int        len;
00443 
00444     BU_CK_VLS(vp);
00445     if( s == (const char *)NULL )  return;
00446     len = strlen(s);
00447     if( len > n )  len = n;
00448     if( len <= 0 )  return;                     /* do nothing */
00449     if( vp->vls_offset + vp->vls_len + len+1 >= vp->vls_max )
00450         bu_vls_extend( vp, len+1 );
00451     bcopy( s, vp->vls_str + vp->vls_offset + vp->vls_len, len );
00452     vp->vls_len += len;
00453     vp->vls_str[vp->vls_offset + vp->vls_len] = '\0';   /* force null termination */
00454 }
00455 
00456 /**
00457  *                      B U _ V L S _ V L S C A T
00458  *
00459  *  Concatenate a new vls string onto the end of an existing vls string.
00460  *  The storage of the source string is not affected.
00461  */
00462 void
00463 bu_vls_vlscat(register struct bu_vls *dest, register const struct bu_vls *src)
00464 {
00465     BU_CK_VLS(src);
00466     BU_CK_VLS(dest);
00467     if( src->vls_len <= 0 )  return;
00468     if( dest->vls_offset + dest->vls_len + src->vls_len+1 >= dest->vls_max )
00469         bu_vls_extend( dest, src->vls_len+1 );
00470     /* copy source string, including null */
00471     bcopy( src->vls_str+src->vls_offset,
00472            dest->vls_str +dest->vls_offset + dest->vls_len,
00473            src->vls_len+1 );
00474     dest->vls_len += src->vls_len;
00475 }
00476 
00477 /**
00478  *                      V L S _ V L S C A T Z A P
00479  *
00480  *  Concatenate a new vls string onto the end of an existing vls string.
00481  *  The storage of the source string is released (zapped).
00482  */
00483 void
00484 bu_vls_vlscatzap(register struct bu_vls *dest, register struct bu_vls *src)
00485 {
00486     BU_CK_VLS(src);
00487     BU_CK_VLS(dest);
00488     if( src->vls_len <= 0 )  return;
00489     bu_vls_vlscat( dest, src );
00490     bu_vls_trunc( src, 0 );
00491 }
00492 
00493 /**
00494  *                      B U _ V L S _ F R O M _ A R G V
00495  *
00496  *  Given and argc & argv pair, convert them into a vls string of space-
00497  *  separated words.
00498  */
00499 void
00500 bu_vls_from_argv(register struct bu_vls *vp, int argc, const char *argv[])
00501 {
00502     BU_CK_VLS(vp);
00503     for( ; argc > 0; argc--, argv++ )  {
00504         bu_vls_strcat( vp, *argv );
00505         if( argc > 1 )  bu_vls_strcat( vp, " " );
00506     }
00507 }
00508 
00509 /**
00510  *                      B U _ A R G V _ F R O M _ S T R I N G
00511  *
00512  *  Build argv[] array from input buffer, by splitting whitespace
00513  *  separated "words" into null terminated strings.
00514  *  The input buffer is altered by this process.
00515  *  The argv[] array points into the input buffer.
00516  *  The input buffer should not be freed until argv has been freed
00517  *  or passes out of scope.
00518  *
00519  *  'lim' indicates the number of elements in the argv[] array.
00520  *
00521  *  Returns -
00522  *       0      no words in input
00523  *      nwords  number of words of input, now in argv[]
00524  *
00525  *  Built from rt_split_cmd(), but without the shell escape support.
00526  */
00527 int
00528 bu_argv_from_string(char **argv, int lim, register char *lp)
00529 {
00530     register int        nwords;                 /* number of words seen */
00531     register char       *lp1;
00532 
00533     argv[0] = "_NIL_";          /* sanity */
00534 
00535     while( *lp != '\0' && isspace( *lp ) )
00536         lp++;
00537 
00538     if( *lp == '\0' )
00539         return 0;               /* No words */
00540 
00541     /* some non-space string has been seen, argv[0] is set */
00542     nwords = 1;
00543     argv[0] = lp;
00544 
00545     for( ; *lp != '\0'; lp++ )  {
00546         if( !isspace( *lp ) )
00547             continue;   /* skip over current word */
00548 
00549         *lp = '\0';             /* terminate current word */
00550         lp1 = lp + 1;
00551         if( *lp1 != '\0' && !isspace( *lp1 ) )  {
00552             /* Begin next word */
00553             if( nwords >= lim-1 )
00554                 break;  /* argv[] full */
00555 
00556             argv[nwords++] = lp1;
00557         }
00558     }
00559     argv[nwords] = (char *)0;   /* safety */
00560     return nwords;
00561 }
00562 
00563 /**
00564  *                      B U _ V L S _ F W R I T E
00565  */
00566 void
00567 bu_vls_fwrite(FILE *fp, const struct bu_vls *vp)
00568 {
00569     int status;
00570 
00571     BU_CK_VLS(vp);
00572     if( vp->vls_len <= 0 )  return;
00573 
00574     bu_semaphore_acquire(BU_SEM_SYSCALL);
00575     status = fwrite( vp->vls_str + vp->vls_offset, vp->vls_len, 1, fp );
00576     bu_semaphore_release(BU_SEM_SYSCALL);
00577 
00578     if( status != 1 ) {
00579         perror("fwrite");
00580         bu_bomb("bu_vls_fwrite() write error\n");
00581     }
00582 }
00583 
00584 /**
00585  *                      B U _ V L S _ W R I T E
00586  */
00587 void
00588 bu_vls_write( int fd, const struct bu_vls *vp )
00589 {
00590 
00591     BU_CK_VLS(vp);
00592     if( vp->vls_len <= 0 )  return;
00593 
00594 #if !defined(HAVE_UNIX_IO)
00595     bu_bomb("bu_vls_write(): This isn't UNIX\n");
00596 #else
00597     {
00598         int status;
00599         bu_semaphore_acquire(BU_SEM_SYSCALL);
00600         status = write( fd, vp->vls_str + vp->vls_offset, vp->vls_len );
00601         bu_semaphore_release(BU_SEM_SYSCALL);
00602 
00603         if( status != vp->vls_len ) {
00604             perror("write");
00605             bu_bomb("bu_vls_write() write error\n");
00606         }
00607     }
00608 #endif
00609 }
00610 
00611 /**
00612  *                      B U _ V L S _ R E A D
00613  *
00614  *  Read the remainder of a UNIX file onto the end of a vls.
00615  *
00616  *  Returns -
00617  *      nread   number of characters read
00618  *      0       if EOF encountered immediately
00619  *      -1      read error
00620  */
00621 int
00622 bu_vls_read( struct bu_vls *vp, int fd )
00623 {
00624     int ret = 0;
00625 
00626     BU_CK_VLS(vp);
00627 
00628 #if !defined(HAVE_UNIX_IO)
00629     bu_bomb("bu_vls_read(): This isn't UNIX\n");
00630 #else
00631     {
00632         int     todo;
00633         int     got;
00634         for(;;)  {
00635             bu_vls_extend( vp, 4096 );
00636             todo = vp->vls_max - vp->vls_len - vp->vls_offset - 1;
00637 
00638             bu_semaphore_acquire(BU_SEM_SYSCALL);
00639             got = read(fd, vp->vls_str+vp->vls_offset+vp->vls_len, todo );
00640             bu_semaphore_release(BU_SEM_SYSCALL);
00641 
00642             if( got < 0 )  {
00643                 /* Read error, abandon the read */
00644                 return -1;
00645             }
00646             if(got == 0)  break;
00647             vp->vls_len += got;
00648             ret += got;
00649         }
00650 
00651         /* force null termination */
00652         vp->vls_str[vp->vls_len+vp->vls_offset] = '\0';
00653     }
00654 #endif
00655     return ret;
00656 }
00657 
00658 /**
00659  *                      B U _ V L S _ G E T S
00660  *
00661  *  Append a newline-terminated string from the file pointed to by "fp"
00662  *  to the end of the vls pointed to by "vp".
00663  *  The newline from the file is read, but not stored into the vls.
00664  *
00665  *  The most common error is to forget to bu_vls_trunc(vp,0) before
00666  *  reading the next line into the vls.
00667  *
00668  *  Returns -
00669  *      >=0     the length of the resulting vls
00670  *       -1     on EOF where no characters were added to the vls.
00671  */
00672 int
00673 bu_vls_gets(register struct bu_vls *vp, register FILE *fp)
00674 {
00675     int startlen;
00676     int c;
00677 
00678     BU_CK_VLS(vp);
00679 
00680     startlen = bu_vls_strlen(vp);
00681     bu_vls_extend( vp, 80 );            /* Ensure room to grow */
00682     for( ;; )  {
00683         /* Talk about inefficiency... */
00684         bu_semaphore_acquire( BU_SEM_SYSCALL );
00685         c = getc(fp);
00686         bu_semaphore_release( BU_SEM_SYSCALL );
00687 
00688         /* XXX Alternatively, code up something with fgets(), chunking */
00689 
00690         if( c == EOF || c == '\n' )  break;
00691         bu_vls_putc( vp, c );
00692     }
00693     if( c == EOF && bu_vls_strlen(vp) <= startlen )  return -1;
00694     vp->vls_str[vp->vls_offset + vp->vls_len] = '\0';   /* force null termination */
00695     return bu_vls_strlen(vp);
00696 }
00697 
00698 /**
00699  *                      B U _ V L S _ P U T C
00700  *
00701  *  Append the given character to the vls.
00702  */
00703 void
00704 bu_vls_putc(register struct bu_vls *vp, int c)
00705 {
00706     BU_CK_VLS(vp);
00707 
00708     if( vp->vls_offset + vp->vls_len+1 >= vp->vls_max )  bu_vls_extend( vp, 80 );
00709     vp->vls_str[vp->vls_offset + vp->vls_len++] = (char)c;
00710     vp->vls_str[vp->vls_offset + vp->vls_len] = '\0';   /* force null termination */
00711 }
00712 
00713 /**
00714  *                      B U _ V L S _ T R I M S P A C E
00715  *
00716  *  Remove leading and trailing white space from a vls string.
00717  */
00718 void
00719 bu_vls_trimspace( struct bu_vls *vp )
00720 {
00721     BU_CK_VLS(vp);
00722 
00723     /* Remove trailing white space */
00724     while( isspace( bu_vls_addr(vp)[bu_vls_strlen(vp)-1] ) )
00725         bu_vls_trunc( vp, -1 );
00726 
00727     /* Remove leading white space */
00728     while( isspace( *bu_vls_addr(vp) ) )
00729         bu_vls_nibble( vp, 1 );
00730 }
00731 
00732 #if defined(HAVE_VARARGS_H) || defined(HAVE_STDARG_H)
00733 /**
00734  *                      B U _ V L S _ V P R I N T F
00735  *
00736  *  Format a string into a vls.  This version should work on practically
00737  *  any machine, but it serves to highlight the the grossness of the varargs
00738  *  package requiring the size of a parameter to be known at compile time.
00739  *
00740  *  %s continues to be a regular 'C' string, null terminated.
00741  *  %S is a pointer to a (struct bu_vls *) string.
00742  *
00743  *  This routine appends to the given vls similar to how vprintf
00744  *  appends to stdout (see bu_vls_vsprintf for overwriting the vls).
00745  */
00746 void
00747 bu_vls_vprintf(struct bu_vls *vls, const char *fmt, va_list ap)
00748 {
00749     register const char *sp;                    /* start pointer */
00750     register const char *ep;                    /* end pointer */
00751     register int len;
00752 
00753 #define LONGINT  0x001
00754 #define FIELDLEN 0x002
00755 #define SHORTINT 0x003
00756 
00757     int flags;
00758     int fieldlen=-1;
00759     char fbuf[64] = {0}, buf[1024] = {0};                       /* % format buffer */
00760 
00761     BU_CK_VLS(vls);
00762     bu_vls_extend(vls, 96);
00763 
00764     sp = fmt;
00765     while( *sp ) {
00766         /* Initial state:  just printing chars */
00767         fmt = sp;
00768         while (*sp != '%' && *sp)
00769             sp++;
00770 
00771         if (sp != fmt)
00772             bu_vls_strncat(vls, fmt, sp-fmt);
00773 
00774         if (*sp == '\0')
00775             break;
00776 
00777         /* Saw a percent sign, find end of fmt specifier */
00778 
00779         flags = 0;
00780         ep = sp;
00781         while( *ep )  {
00782             ++ep;
00783             if (*ep == ' ' || *ep == '#' || *ep == '-' ||
00784                 *ep == '+' || *ep == '.' || isdigit(*ep))
00785                 continue;
00786             else if (*ep == 'l' || *ep == 'U' || *ep == 'O')
00787                 flags |= LONGINT;
00788             else if (*ep == '*') {
00789                 fieldlen = va_arg(ap, int);
00790                 flags |= FIELDLEN;
00791             } else if (*ep == 'h') {
00792                 flags |= SHORTINT;
00793             } else
00794                 /* Anything else must be the end of the fmt specifier */
00795                 break;
00796         }
00797 
00798         /* Copy off the format string */
00799         len = ep-sp+1;
00800         if (len > sizeof(fbuf)-1) len = sizeof(fbuf)-1;
00801         strncpy(fbuf, sp, len);
00802         fbuf[len] = '\0'; /* ensure null termination */
00803 
00804         /* Grab parameter from arg list, and print it */
00805         switch( *ep ) {
00806             case 's':
00807                 {
00808                     register char *str;
00809 
00810                     str = va_arg(ap, char *);
00811                     if (str)  {
00812                         if (flags & FIELDLEN) {
00813                             int stringlen = strlen(str);
00814                             int left_justify;
00815 
00816                             if ((left_justify = (fieldlen < 0)))
00817                                 fieldlen *= -1;
00818 
00819                             if (stringlen >= fieldlen)
00820                                 bu_vls_strncat(vls, str, fieldlen);
00821                             else {
00822                                 struct bu_vls           padded;
00823                                 int                     i;
00824 
00825                                 bu_vls_init(&padded);
00826                                 if (left_justify)
00827                                     bu_vls_strcat(&padded, str);
00828                                 for (i = 0; i < fieldlen - stringlen; ++i)
00829                                     bu_vls_putc(&padded, ' ');
00830                                 if (!left_justify)
00831                                     bu_vls_strcat(&padded, str);
00832                                 bu_vls_vlscat(vls, &padded);
00833                             }
00834                         } else {
00835                             bu_vls_strcat(vls, str);
00836                         }
00837                     }  else  {
00838                         if (flags & FIELDLEN)
00839                             bu_vls_strncat(vls, "(null)", fieldlen);
00840                         else
00841                             bu_vls_strcat(vls, "(null)");
00842                     }
00843                 }
00844                 break;
00845             case 'S':
00846                 {
00847                     register struct bu_vls *vp;
00848 
00849                     vp = va_arg(ap, struct bu_vls *);
00850                     if (vp) {
00851                         BU_CK_VLS(vp);
00852                         if (flags & FIELDLEN) {
00853                             int stringlen = bu_vls_strlen(vp);
00854                             int left_justify;
00855 
00856                             if ((left_justify = (fieldlen < 0)))
00857                                 fieldlen *= -1;
00858 
00859                             if (stringlen >= fieldlen)
00860                                 bu_vls_strncat(vls, bu_vls_addr(vp), fieldlen);
00861                             else {
00862                                 struct bu_vls           padded;
00863                                 int                     i;
00864 
00865                                 bu_vls_init(&padded);
00866                                 if (left_justify)
00867                                     bu_vls_vlscat(&padded, vp);
00868                                 for (i = 0; i < fieldlen - stringlen; ++i)
00869                                     bu_vls_putc(&padded, ' ');
00870                                 if (!left_justify)
00871                                     bu_vls_vlscat(&padded, vp);
00872                                 bu_vls_vlscat(vls, &padded);
00873                             }
00874                         } else {
00875                             bu_vls_vlscat(vls, vp);
00876                         }
00877                     }  else  {
00878                         if (flags & FIELDLEN)
00879                             bu_vls_strncat(vls, "(null)", fieldlen);
00880                         else
00881                             bu_vls_strcat(vls, "(null)");
00882                     }
00883                 }
00884                 break;
00885             case 'e':
00886             case 'E':
00887             case 'f':
00888             case 'g':
00889             case 'G':
00890                 /* All floating point ==> "double" */
00891 #if defined(LONGDBL)
00892                 if (flags & LONGDBL) {
00893                     register long double ld;
00894 
00895                     ld = va_arg(ap, long double);
00896                     if (flags & FIELDLEN)
00897                         sprintf(buf, fbuf, fieldlen, ld);
00898                     else
00899                         sprintf(buf, fbuf, ld);
00900                     bu_vls_strcat(vls, buf);
00901                 } else
00902 #endif
00903                     {
00904                         register double d;
00905 
00906                         d = va_arg(ap, double);
00907                         if (flags & FIELDLEN)
00908                             sprintf(buf, fbuf, fieldlen, d);
00909                         else
00910                             sprintf(buf, fbuf, d);
00911                         bu_vls_strcat(vls, buf);
00912                     }
00913                 break;
00914             case 'd':
00915             case 'x':
00916                 if (flags & LONGINT) {
00917                     /* Long int */
00918                     register long ll;
00919 
00920                     ll = va_arg(ap, long);
00921                     if (flags & FIELDLEN)
00922                         sprintf(buf, fbuf, fieldlen, ll);
00923                     else
00924                         sprintf(buf, fbuf, ll);
00925                     bu_vls_strcat(vls, buf);
00926                 } else if (flags & SHORTINT) {
00927                     /* short int */
00928                     register short int sh;
00929                     sh = (short int)va_arg(ap, int);
00930                     if (flags & FIELDLEN)
00931                         sprintf(buf, fbuf, fieldlen, sh);
00932                     else
00933                         sprintf(buf, fbuf, sh);
00934                     bu_vls_strcat(vls, buf);
00935                 } else {
00936                     /* Regular int */
00937                     register int j;
00938 
00939                     j = va_arg(ap, int);
00940                     if (flags & FIELDLEN)
00941                         sprintf(buf, fbuf, fieldlen, j);
00942                     else
00943                         sprintf(buf, fbuf, j);
00944                     bu_vls_strcat(vls, buf);
00945                 }
00946                 break;
00947             case '%':
00948                 bu_vls_putc(vls, '%');
00949                 break;
00950             default:  /* Something weird, maybe %c */
00951                 {
00952                     register int j;
00953 
00954                     /* We hope, whatever it is, it fits in an int and the resulting
00955                        stringlet is smaller than sizeof(buf) bytes */
00956 
00957                     j = va_arg(ap, int);
00958                     if (flags & FIELDLEN)
00959                         sprintf(buf, fbuf, fieldlen, j);
00960                     else
00961                         sprintf(buf, fbuf, j);
00962                     bu_vls_strcat(vls, buf);
00963                     break;
00964                 }
00965         }
00966         sp = ep+1;
00967     }
00968 
00969     va_end(ap);
00970 }
00971 #else
00972 #  error "No implementation provided for bu_vls_vprintf()"
00973 #endif  /* !defined(HAVE_VARARGS_H) && !defined(HAVE_STDARG_H) */
00974 
00975 
00976 #if defined(HAVE_STDARG_H)
00977 /**
00978  *                 B U _ V L S _ P R I N T F
00979  *
00980  * Initializes the va_list, then calls the above bu_vls_vprintf.
00981  */
00982 void
00983 bu_vls_printf(struct bu_vls *vls, char *fmt, ...)  /* ANSI C */
00984 {
00985     va_list ap;
00986     va_start(ap, fmt);
00987     BU_CK_VLS(vls);
00988     bu_vls_vprintf(vls, fmt, ap);
00989     va_end(ap);
00990 }
00991 
00992 #else  /* !HAVE_STDARG_H */
00993 #  if defined(HAVE_VARARGS_H)
00994 
00995 void
00996 bu_vls_printf(va_dcl va_alist)                            /* VARARGS */
00997 {
00998     va_list ap;
00999     struct bu_vls *vls;
01000     char *fmt;
01001 
01002     va_start(ap);
01003     vls = va_arg(ap, struct bu_vls *);
01004     fmt = va_arg(ap, char *);
01005     BU_CK_VLS(vls);
01006     bu_vls_vprintf(vls, fmt, ap);
01007     va_end(ap);
01008 }
01009 
01010 #  else  /* !HAVE_VARARGS_H */
01011 
01012 void
01013 bu_vls_printf(struct bu_vls *vls, char *fmt, a,b,c,d,e,f,g,h,i,j)       /* Cray XMP */
01014 {
01015     char append_buf[65536] = {0};   /* yuck -- fixed length buffer. */
01016 
01017     BU_CK_VLS(vls);
01018     sprintf(append_buf, fmt, a,b,c,d,e,f,g,h,i,j);
01019     if (append_buf[sizeof(append_buf)-1] != '\0') {
01020         /* Attempting to bu_log() the WHOLE append_buf would just overflow again */
01021         append_buf[120] = '\0';
01022         bu_log("bu_vls_printf buffer overflow\nWhile building string '%s'...\n",
01023                append_buf);
01024         bu_bomb("bu_vls_printf buffer overflow\n");
01025     }
01026 
01027     bu_vls_strcat(vls, append_buf);
01028 }
01029 #  endif  /* HAVE_VARARGS_H */
01030 #endif  /* HAVE_STDARG_H */
01031 
01032 
01033 #if defined(HAVE_STDARG_H)
01034 
01035 /**
01036  *                      B U _ V L S _ S P R I N T F
01037  *
01038  *  Format a string into a vls, setting the vls to the given print
01039  *  specifier expansion.  This routine truncates any existing vls
01040  *  contents beforehand (i.e. it doesn't append, see bu_vls_vprintf
01041  *  for appending to the vls).
01042  *
01043  *  %s continues to be a regular 'C' string, null terminated.
01044  *  %S is a pointer to a (struct bu_vls *) string.
01045  */
01046 void
01047 bu_vls_sprintf(struct bu_vls *vls, char *fmt, ...)  /* ANSI C */
01048 {
01049     va_list ap;
01050     va_start(ap, fmt);
01051     BU_CK_VLS(vls);
01052     bu_vls_trunc(vls, 0); /* poof */
01053     bu_vls_vprintf(vls, fmt, ap);
01054     va_end(ap);
01055 }
01056 
01057 #else  /* !HAVE_STDARG_H */
01058 #  if defined(HAVE_VARARGS_H)
01059 
01060 void
01061 bu_vls_sprintf(va_dcl va_alist)                            /* VARARGS */
01062 {
01063     va_list ap;
01064     struct bu_vls *vls;
01065     char *fmt;
01066 
01067     va_start(ap);
01068     vls = va_arg(ap, struct bu_vls *);
01069     fmt = va_arg(ap, char *);
01070     BU_CK_VLS(vls);
01071     bu_vls_trunc(vls, 0); /* poof */
01072     bu_vls_vprintf(vls, fmt, ap);
01073     va_end(ap);
01074 }
01075 
01076 #  else  /* !HAVE_VARARGS_H */
01077 
01078 void
01079 bu_vls_sprintf(struct bu_vls *vls, char *fmt, a,b,c,d,e,f,g,h,i,j)       /* Cray XMP */
01080 {
01081     BU_CK_VLS(vls);
01082     bu_vls_trunc(vls, 0); /* poof */
01083     bu_vls_printf(vls, fmt, a, b, c, d, e, f, g, h, i, j);
01084 }
01085 #  endif  /* HAVE_VARARGS_H */
01086 #endif  /* HAVE_STDARG_H */
01087 
01088 /**
01089  *                      B U _ V L S _ S P A C E S
01090  *
01091  *  Efficiently append 'cnt' spaces to the current vls.
01092  */
01093 void
01094 bu_vls_spaces(register struct bu_vls *vp, int cnt)
01095 {
01096     BU_CK_VLS(vp);
01097     if( cnt <= 0 )  return;
01098     if( vp->vls_offset + vp->vls_len + cnt+1 >= vp->vls_max )
01099         bu_vls_extend( vp, cnt );
01100     memset( vp->vls_str + vp->vls_offset + vp->vls_len, ' ', cnt );
01101     vp->vls_len += cnt;
01102 }
01103 
01104 /**
01105  *                      B U _ V L S _ P R I N T _ P O S I T I O N S _ U S E D
01106  *
01107  *  Returns number of printed spaces used on final output line of a
01108  *  potentially multi-line vls.  Useful for making decisions on when
01109  *  to line-wrap.
01110  *  Accounts for normal UNIX tab-expansion:
01111  *               1         2         3         4
01112  *      1234567890123456789012345678901234567890
01113  *              x       x       x       x
01114  *
01115  *      0-7 --> 8, 8-15 --> 16, 16-23 --> 24, etc.
01116  */
01117 int
01118 bu_vls_print_positions_used(const struct bu_vls *vp)
01119 {
01120     char        *start;
01121     int used;
01122 
01123     BU_CK_VLS(vp);
01124 
01125     if( (start = strrchr( bu_vls_addr(vp), '\n' )) == NULL )
01126         start = bu_vls_addr(vp);
01127     used = 0;
01128     while( *start != '\0' )  {
01129         if( *start == '\t' )  {
01130             used += 8 - (used % 8);
01131         } else {
01132             used++;
01133         }
01134         start++;
01135     }
01136     return used;
01137 }
01138 
01139 /**
01140  *                      B U _ V L S _ D E T A B
01141  *
01142  *  Given a vls, return a version of that string which has had all
01143  *  "tab" characters converted to the appropriate number of spaces
01144  *  according to the UNIX tab convention.
01145  */
01146 void
01147 bu_vls_detab(struct bu_vls *vp)
01148 {
01149     struct bu_vls       src;
01150     register char       *cp;
01151     int         used;
01152 
01153     BU_CK_VLS(vp);
01154     bu_vls_init( &src );
01155     bu_vls_vlscatzap( &src, vp );       /* make temporary copy of src */
01156     bu_vls_extend( vp, bu_vls_strlen(&src)+50 );
01157 
01158     cp = bu_vls_addr( &src );
01159     used = 0;
01160     while( *cp != '\0' )  {
01161         if( *cp == '\t' )  {
01162             int todo;
01163             todo = 8 - (used % 8);
01164             bu_vls_spaces( vp, todo );
01165             used += todo;
01166         } else if( *cp == '\n' )  {
01167             bu_vls_putc( vp, '\n' );
01168             used = 0;
01169         } else {
01170             bu_vls_putc( vp, *cp );
01171             used++;
01172         }
01173         cp++;
01174     }
01175     bu_vls_free( &src );
01176 }
01177 
01178 /**
01179  *              B U _ V L S _ P R E P E N D
01180  *
01181  *  Add a string to the begining of the vls.
01182  */
01183 void
01184 bu_vls_prepend(struct bu_vls *vp, char *str)
01185 {
01186     int len = strlen(str);
01187 
01188     bu_vls_extend(vp, len);
01189 
01190     /* memmove is supposed to be safe even if strings overlap */
01191     memmove( vp->vls_str+vp->vls_offset+len, vp->vls_str+vp->vls_offset, vp->vls_len );
01192 
01193     /* insert the data at the head of the string */
01194     memcpy( vp->vls_str+vp->vls_offset, str, len);
01195 }
01196 /*@}*/
01197 
01198 /*
01199  * Local Variables:
01200  * mode: C
01201  * tab-width: 8
01202  * c-basic-offset: 4
01203  * indent-tabs-mode: t
01204  * End:
01205  * ex: shiftwidth=4 tabstop=8
01206  */

Generated on Mon Sep 18 01:24:48 2006 for BRL-CAD by  doxygen 1.4.6