Blender V2.61 - r43446

BLI_dynstr.c

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