Blender  V2.59
BLI_dynstr.c
Go to the documentation of this file.
00001 /*
00002  * $Id: BLI_dynstr.c 35246 2011-02-27 20:37:56Z jesterking $
00003  *
00004  * ***** BEGIN GPL LICENSE BLOCK *****
00005  *
00006  * This program is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU General Public License
00008  * as published by the Free Software Foundation; either version 2
00009  * of the License, or (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software Foundation,
00018  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00019  *
00020  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
00021  * All rights reserved.
00022  *
00023  * The Original Code is: all of this file.
00024  *
00025  * Contributor(s): none yet.
00026  *
00027  * ***** END GPL LICENSE BLOCK *****
00028  * Dynamically sized string ADT
00029  */
00030 
00036 #include <stdarg.h>
00037 #include <string.h>
00038 
00039 #include "MEM_guardedalloc.h"
00040 #include "BLI_blenlib.h"
00041 #include "BLI_dynstr.h"
00042 
00043 #ifdef _WIN32
00044 #ifndef vsnprintf
00045 #define vsnprintf _vsnprintf
00046 #endif
00047 #endif
00048 
00049 #ifndef va_copy
00050 # ifdef __va_copy
00051 #  define va_copy(a,b) __va_copy(a,b)
00052 # else /* !__va_copy */
00053 #  define va_copy(a,b) ((a)=(b))
00054 # endif /* __va_copy */
00055 #endif /* va_copy */
00056 
00057 /***/
00058 
00059 typedef struct DynStrElem DynStrElem;
00060 struct DynStrElem {
00061         DynStrElem *next;
00062         
00063         char *str;
00064 };
00065 
00066 struct DynStr {
00067         DynStrElem *elems, *last;
00068         int curlen;
00069 };
00070 
00071 /***/
00072 
00073 DynStr *BLI_dynstr_new(void) {
00074         DynStr *ds= MEM_mallocN(sizeof(*ds), "DynStr");
00075         ds->elems= ds->last= NULL;
00076         ds->curlen= 0;
00077         
00078         return ds;
00079 }
00080 
00081 void BLI_dynstr_append(DynStr *ds, const char *cstr) {
00082         DynStrElem *dse= malloc(sizeof(*dse));
00083         int cstrlen= strlen(cstr);
00084         
00085         dse->str= malloc(cstrlen+1);
00086         memcpy(dse->str, cstr, cstrlen+1);
00087         dse->next= NULL;
00088         
00089         if (!ds->last)
00090                 ds->last= ds->elems= dse;
00091         else
00092                 ds->last= ds->last->next= dse;
00093 
00094         ds->curlen+= cstrlen;
00095 }
00096 
00097 void BLI_dynstr_nappend(DynStr *ds, const char *cstr, int len) {
00098         DynStrElem *dse= malloc(sizeof(*dse));
00099         int cstrlen= BLI_strnlen(cstr, len);
00100 
00101         dse->str= malloc(cstrlen+1);
00102         memcpy(dse->str, cstr, cstrlen);
00103         dse->str[cstrlen] = '\0';
00104         dse->next= NULL;
00105 
00106         if (!ds->last)
00107                 ds->last= ds->elems= dse;
00108         else
00109                 ds->last= ds->last->next= dse;
00110 
00111         ds->curlen+= cstrlen;
00112 }
00113 
00114 void BLI_dynstr_vappendf(DynStr *ds, const char *format, va_list args)
00115 {
00116         char *message, fixedmessage[256];
00117         int len= sizeof(fixedmessage);
00118         const int maxlen= 65536;
00119         int retval;
00120 
00121         while(1) {
00122                 va_list args_cpy;
00123                 if(len == sizeof(fixedmessage))
00124                         message= fixedmessage;
00125                 else
00126                         message= MEM_callocN(sizeof(char) * len, "BLI_dynstr_appendf");
00127 
00128                 /* cant reuse the same args, so work on a copy */
00129                 va_copy(args_cpy, args);
00130                 retval= vsnprintf(message, len, format, args_cpy);
00131                 va_end(args_cpy);
00132 
00133                 if(retval == -1) {
00134                         /* -1 means not enough space, but on windows it may also mean
00135                          * there is a formatting error, so we impose a maximum length */
00136                         if(message != fixedmessage)
00137                                 MEM_freeN(message);
00138                         message= NULL;
00139 
00140                         len *= 2;
00141                         if(len > maxlen) {
00142                                 fprintf(stderr, "BLI_dynstr_append text too long or format error.\n");
00143                                 break;
00144                         }
00145                 }
00146                 else if(retval >= len) {
00147                         /* in C99 the actual length required is returned */
00148                         if(message != fixedmessage)
00149                                 MEM_freeN(message);
00150                         message= NULL;
00151 
00152                         /* retval doesnt include \0 terminator */
00153                         len= retval + 1;
00154                 }
00155                 else
00156                         break;
00157         }
00158 
00159         if(message) {
00160                 BLI_dynstr_append(ds, message);
00161 
00162                 if(message != fixedmessage)
00163                         MEM_freeN(message);
00164         }
00165 }
00166 
00167 void BLI_dynstr_appendf(DynStr *ds, const char *format, ...)
00168 {
00169         va_list args;
00170         char *message, fixedmessage[256];
00171         int len= sizeof(fixedmessage);
00172         const int maxlen= 65536;
00173         int retval;
00174 
00175         /* note that it's tempting to just call BLI_dynstr_vappendf here
00176          * and avoid code duplication, that crashes on some system because
00177          * va_start/va_end have to be called for each vsnprintf call */
00178 
00179         while(1) {
00180                 if(len == sizeof(fixedmessage))
00181                         message= fixedmessage;
00182                 else
00183                         message= MEM_callocN(sizeof(char)*(len), "BLI_dynstr_appendf");
00184 
00185                 va_start(args, format);
00186                 retval= vsnprintf(message, len, format, args);
00187                 va_end(args);
00188 
00189                 if(retval == -1) {
00190                         /* -1 means not enough space, but on windows it may also mean
00191                          * there is a formatting error, so we impose a maximum length */
00192                         if(message != fixedmessage)
00193                                 MEM_freeN(message);
00194                         message= NULL;
00195 
00196                         len *= 2;
00197                         if(len > maxlen) {
00198                                 fprintf(stderr, "BLI_dynstr_append text too long or format error.\n");
00199                                 break;
00200                         }
00201                 }
00202                 else if(retval >= len) {
00203                         /* in C99 the actual length required is returned */
00204                         if(message != fixedmessage)
00205                                 MEM_freeN(message);
00206                         message= NULL;
00207 
00208                         /* retval doesnt include \0 terminator */
00209                         len= retval + 1;
00210                 }
00211                 else
00212                         break;
00213         }
00214 
00215         if(message) {
00216                 BLI_dynstr_append(ds, message);
00217 
00218                 if(message != fixedmessage)
00219                         MEM_freeN(message);
00220         }
00221 }
00222 
00223 int BLI_dynstr_get_len(DynStr *ds) {
00224         return ds->curlen;
00225 }
00226 
00227 char *BLI_dynstr_get_cstring(DynStr *ds) {
00228         char *s, *rets= MEM_mallocN(ds->curlen+1, "dynstr_cstring");
00229         DynStrElem *dse;
00230         
00231         for (s= rets, dse= ds->elems; dse; dse= dse->next) {
00232                 int slen= strlen(dse->str);
00233 
00234                 memcpy(s, dse->str, slen);
00235 
00236                 s+= slen;
00237         }
00238         rets[ds->curlen]= '\0';
00239         
00240         return rets;
00241 }
00242 
00243 void BLI_dynstr_free(DynStr *ds) {
00244         DynStrElem *dse;
00245         
00246         for (dse= ds->elems; dse; ) {
00247                 DynStrElem *n= dse->next;
00248                 
00249                 free(dse->str);
00250                 free(dse);
00251                 
00252                 dse= n;
00253         }
00254         
00255         MEM_freeN(ds);
00256 }