Blender  V2.59
listbase.c
Go to the documentation of this file.
00001 /* util.c
00002  *
00003  * various string, file, list operations.
00004  *
00005  *
00006  * $Id: listbase.c 36442 2011-05-02 13:35:04Z campbellbarton $
00007  *
00008  * ***** BEGIN GPL LICENSE BLOCK *****
00009  *
00010  * This program is free software; you can redistribute it and/or
00011  * modify it under the terms of the GNU General Public License
00012  * as published by the Free Software Foundation; either version 2
00013  * of the License, or (at your option) any later version.
00014  *
00015  * This program is distributed in the hope that it will be useful,
00016  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018  * GNU General Public License for more details.
00019  *
00020  * You should have received a copy of the GNU General Public License
00021  * along with this program; if not, write to the Free Software Foundation,
00022  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00023  *
00024  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
00025  * All rights reserved.
00026  *
00027  * The Original Code is: all of this file.
00028  *
00029  * Contributor(s): none yet.
00030  *
00031  * ***** END GPL LICENSE BLOCK *****
00032  * 
00033  */
00034 
00040 #include <string.h>
00041 #include <stdlib.h>
00042 
00043 
00044 #include "MEM_guardedalloc.h"
00045 
00046 #include "DNA_listBase.h"
00047 
00048 #include "BLI_listbase.h"
00049 
00050 
00051 /* implementation */
00052 
00053 /* Ripped this from blender.c */
00054 void BLI_movelisttolist(ListBase *dst, ListBase *src)
00055 {
00056         if (src->first==NULL) return;
00057 
00058         if (dst->first==NULL) {
00059                 dst->first= src->first;
00060                 dst->last= src->last;
00061         }
00062         else {
00063                 ((Link *)dst->last)->next= src->first;
00064                 ((Link *)src->first)->prev= dst->last;
00065                 dst->last= src->last;
00066         }
00067         src->first= src->last= NULL;
00068 }
00069 
00070 void BLI_addhead(ListBase *listbase, void *vlink)
00071 {
00072         Link *link= vlink;
00073 
00074         if (link == NULL) return;
00075         if (listbase == NULL) return;
00076 
00077         link->next = listbase->first;
00078         link->prev = NULL;
00079 
00080         if (listbase->first) ((Link *)listbase->first)->prev = link;
00081         if (listbase->last == NULL) listbase->last = link;
00082         listbase->first = link;
00083 }
00084 
00085 
00086 void BLI_addtail(ListBase *listbase, void *vlink)
00087 {
00088         Link *link= vlink;
00089 
00090         if (link == NULL) return;
00091         if (listbase == NULL) return;
00092 
00093         link->next = NULL;
00094         link->prev = listbase->last;
00095 
00096         if (listbase->last) ((Link *)listbase->last)->next = link;
00097         if (listbase->first == NULL) listbase->first = link;
00098         listbase->last = link;
00099 }
00100 
00101 
00102 void BLI_remlink(ListBase *listbase, void *vlink)
00103 {
00104         Link *link= vlink;
00105 
00106         if (link == NULL) return;
00107         if (listbase == NULL) return;
00108 
00109         if (link->next) link->next->prev = link->prev;
00110         if (link->prev) link->prev->next = link->next;
00111 
00112         if (listbase->last == link) listbase->last = link->prev;
00113         if (listbase->first == link) listbase->first = link->next;
00114 }
00115 
00116 int BLI_remlink_safe(ListBase *listbase, void *vlink)
00117 {
00118         if(BLI_findindex(listbase, vlink) != -1) {
00119                 BLI_remlink(listbase, vlink);
00120                 return 1;
00121         }
00122         else {
00123                 return 0;
00124         }
00125 }
00126 
00127 
00128 void BLI_freelinkN(ListBase *listbase, void *vlink)
00129 {
00130         Link *link= vlink;
00131 
00132         if (link == NULL) return;
00133         if (listbase == NULL) return;
00134 
00135         BLI_remlink(listbase,link);
00136         MEM_freeN(link);
00137 }
00138 
00139 
00140 void BLI_insertlink(ListBase *listbase, void *vprevlink, void *vnewlink)
00141 {
00142         Link *prevlink= vprevlink;
00143         Link *newlink= vnewlink;
00144 
00145         /* newlink comes after prevlink */
00146         if (newlink == NULL) return;
00147         if (listbase == NULL) return;
00148         
00149         /* empty list */
00150         if (listbase->first == NULL) { 
00151                 
00152                 listbase->first= newlink;
00153                 listbase->last= newlink;
00154                 return;
00155         }
00156         
00157         /* insert before first element */
00158         if (prevlink == NULL) { 
00159                 newlink->next= listbase->first;
00160                 newlink->prev= NULL;
00161                 newlink->next->prev= newlink;
00162                 listbase->first= newlink;
00163                 return;
00164         }
00165 
00166         /* at end of list */
00167         if (listbase->last== prevlink) 
00168                 listbase->last = newlink;
00169 
00170         newlink->next= prevlink->next;
00171         prevlink->next= newlink;
00172         if (newlink->next) newlink->next->prev= newlink;
00173         newlink->prev= prevlink;
00174 }
00175 
00176 /* This uses insertion sort, so NOT ok for large list */
00177 void BLI_sortlist(ListBase *listbase, int (*cmp)(void *, void *))
00178 {
00179         Link *current = NULL;
00180         Link *previous = NULL;
00181         Link *next = NULL;
00182         
00183         if (cmp == NULL) return;
00184         if (listbase == NULL) return;
00185 
00186         if (listbase->first != listbase->last)
00187         {
00188                 for( previous = listbase->first, current = previous->next; current; current = next )
00189                 {
00190                         next = current->next;
00191                         previous = current->prev;
00192                         
00193                         BLI_remlink(listbase, current);
00194                         
00195                         while(previous && cmp(previous, current) == 1)
00196                         {
00197                                 previous = previous->prev;
00198                         }
00199                         
00200                         BLI_insertlinkafter(listbase, previous, current);
00201                 }
00202         }
00203 }
00204 
00205 void BLI_insertlinkafter(ListBase *listbase, void *vprevlink, void *vnewlink)
00206 {
00207         Link *prevlink= vprevlink;
00208         Link *newlink= vnewlink;
00209 
00210         /* newlink before nextlink */
00211         if (newlink == NULL) return;
00212         if (listbase == NULL) return;
00213 
00214         /* empty list */
00215         if (listbase->first == NULL) { 
00216                 listbase->first= newlink;
00217                 listbase->last= newlink;
00218                 return;
00219         }
00220         
00221         /* insert at head of list */
00222         if (prevlink == NULL) { 
00223                 newlink->prev = NULL;
00224                 newlink->next = listbase->first;
00225                 ((Link *)listbase->first)->prev = newlink;
00226                 listbase->first = newlink;
00227                 return;
00228         }
00229 
00230         /* at end of list */
00231         if (listbase->last == prevlink) 
00232                 listbase->last = newlink;
00233 
00234         newlink->next = prevlink->next;
00235         newlink->prev = prevlink;
00236         prevlink->next = newlink;
00237         if (newlink->next) newlink->next->prev = newlink;
00238 }
00239 
00240 void BLI_insertlinkbefore(ListBase *listbase, void *vnextlink, void *vnewlink)
00241 {
00242         Link *nextlink= vnextlink;
00243         Link *newlink= vnewlink;
00244 
00245         /* newlink before nextlink */
00246         if (newlink == NULL) return;
00247         if (listbase == NULL) return;
00248 
00249         /* empty list */
00250         if (listbase->first == NULL) { 
00251                 listbase->first= newlink;
00252                 listbase->last= newlink;
00253                 return;
00254         }
00255         
00256         /* insert at end of list */
00257         if (nextlink == NULL) { 
00258                 newlink->prev= listbase->last;
00259                 newlink->next= NULL;
00260                 ((Link *)listbase->last)->next= newlink;
00261                 listbase->last= newlink;
00262                 return;
00263         }
00264 
00265         /* at beginning of list */
00266         if (listbase->first== nextlink) 
00267                 listbase->first = newlink;
00268 
00269         newlink->next= nextlink;
00270         newlink->prev= nextlink->prev;
00271         nextlink->prev= newlink;
00272         if (newlink->prev) newlink->prev->next= newlink;
00273 }
00274 
00275 
00276 void BLI_freelist(ListBase *listbase)
00277 {
00278         Link *link, *next;
00279 
00280         if (listbase == NULL) 
00281                 return;
00282         
00283         link= listbase->first;
00284         while (link) {
00285                 next= link->next;
00286                 free(link);
00287                 link= next;
00288         }
00289         
00290         listbase->first= NULL;
00291         listbase->last= NULL;
00292 }
00293 
00294 void BLI_freelistN(ListBase *listbase)
00295 {
00296         Link *link, *next;
00297 
00298         if (listbase == NULL) return;
00299         
00300         link= listbase->first;
00301         while (link) {
00302                 next= link->next;
00303                 MEM_freeN(link);
00304                 link= next;
00305         }
00306         
00307         listbase->first= NULL;
00308         listbase->last= NULL;
00309 }
00310 
00311 
00312 int BLI_countlist(const ListBase *listbase)
00313 {
00314         Link *link;
00315         int count = 0;
00316         
00317         if (listbase) {
00318                 link = listbase->first;
00319                 while (link) {
00320                         count++;
00321                         link= link->next;
00322                 }
00323         }
00324         return count;
00325 }
00326 
00327 void *BLI_findlink(const ListBase *listbase, int number)
00328 {
00329         Link *link = NULL;
00330 
00331         if (number >= 0) {
00332                 link = listbase->first;
00333                 while (link != NULL && number != 0) {
00334                         number--;
00335                         link = link->next;
00336                 }
00337         }
00338 
00339         return link;
00340 }
00341 
00342 int BLI_findindex(const ListBase *listbase, void *vlink)
00343 {
00344         Link *link= NULL;
00345         int number= 0;
00346         
00347         if (listbase == NULL) return -1;
00348         if (vlink == NULL) return -1;
00349         
00350         link= listbase->first;
00351         while (link) {
00352                 if (link == vlink)
00353                         return number;
00354                 
00355                 number++;
00356                 link= link->next;
00357         }
00358         
00359         return -1;
00360 }
00361 
00362 void *BLI_findstring(const ListBase *listbase, const char *id, const int offset)
00363 {
00364         Link *link= NULL;
00365         const char *id_iter;
00366 
00367         if (listbase == NULL) return NULL;
00368 
00369         for (link= listbase->first; link; link= link->next) {
00370                 id_iter= ((const char *)link) + offset;
00371 
00372                 if (id[0] == id_iter[0] && strcmp(id, id_iter)==0) {
00373                         return link;
00374                 }
00375         }
00376 
00377         return NULL;
00378 }
00379 /* same as above but find reverse */
00380 void *BLI_rfindstring(const ListBase *listbase, const char *id, const int offset)
00381 {
00382         Link *link= NULL;
00383         const char *id_iter;
00384 
00385         if (listbase == NULL) return NULL;
00386 
00387         for (link= listbase->last; link; link= link->prev) {
00388                 id_iter= ((const char *)link) + offset;
00389 
00390                 if (id[0] == id_iter[0] && strcmp(id, id_iter)==0) {
00391                         return link;
00392                 }
00393         }
00394 
00395         return NULL;
00396 }
00397 
00398 void *BLI_findstring_ptr(const ListBase *listbase, const char *id, const int offset)
00399 {
00400         Link *link= NULL;
00401         const char *id_iter;
00402 
00403         if (listbase == NULL) return NULL;
00404 
00405         for (link= listbase->first; link; link= link->next) {
00406                 /* exact copy of BLI_findstring(), except for this line */
00407                 id_iter= *((const char **)(((const char *)link) + offset));
00408 
00409                 if (id[0] == id_iter[0] && strcmp(id, id_iter)==0) {
00410                         return link;
00411                 }
00412         }
00413 
00414         return NULL;
00415 }
00416 /* same as above but find reverse */
00417 void *BLI_rfindstring_ptr(const ListBase *listbase, const char *id, const int offset)
00418 {
00419         Link *link= NULL;
00420         const char *id_iter;
00421 
00422         if (listbase == NULL) return NULL;
00423 
00424         for (link= listbase->last; link; link= link->prev) {
00425                 /* exact copy of BLI_rfindstring(), except for this line */
00426                 id_iter= *((const char **)(((const char *)link) + offset));
00427 
00428                 if (id[0] == id_iter[0] && strcmp(id, id_iter)==0) {
00429                         return link;
00430                 }
00431         }
00432 
00433         return NULL;
00434 }
00435 
00436 int BLI_findstringindex(const ListBase *listbase, const char *id, const int offset)
00437 {
00438         Link *link= NULL;
00439         const char *id_iter;
00440         int i= 0;
00441 
00442         if (listbase == NULL) return -1;
00443 
00444         link= listbase->first;
00445         while (link) {
00446                 id_iter= ((const char *)link) + offset;
00447 
00448                 if(id[0] == id_iter[0] && strcmp(id, id_iter)==0)
00449                         return i;
00450                 i++;
00451                 link= link->next;
00452         }
00453 
00454         return -1;
00455 }
00456 
00457 void BLI_duplicatelist(ListBase *dst, const ListBase *src)
00458 {
00459         struct Link *dst_link, *src_link;
00460 
00461         /* in this order, to ensure it works if dst == src */
00462         src_link= src->first;
00463         dst->first= dst->last= NULL;
00464 
00465         while(src_link) {
00466                 dst_link= MEM_dupallocN(src_link);
00467                 BLI_addtail(dst, dst_link);
00468 
00469                 src_link= src_link->next;
00470         }
00471 }
00472 
00473 /* create a generic list node containing link to provided data */
00474 LinkData *BLI_genericNodeN (void *data)
00475 {
00476         LinkData *ld;
00477         
00478         if (data == NULL)
00479                 return NULL;
00480                 
00481         /* create new link, and make it hold the given data */
00482         ld= MEM_callocN(sizeof(LinkData), "BLI_genericNodeN()");
00483         ld->data= data;
00484         
00485         return ld;
00486 }