From b8e425af7c24ee24ee43205b0ce6e66e6a6a0c22 Mon Sep 17 00:00:00 2001 From: Ken Hughes Date: Thu, 29 Mar 2007 04:55:29 +0000 Subject: [PATCH] Revisions to previous change of new_id(). Note: the intent of the original modification (and these updates) is not to change how new_id() functions. What has been done is to pull out the code which calculates a new name for an ID in the case of duplicate, as would happen when you copy any datablock, into a separate function. This code is necessary in the new Python Library module, since it otherwise is extremely difficult to locate a new datablock appended from a library. new_id() calls this separate function to generate a name for the new ID if necessary, just as it previously did. To make the purpose of this new function clearer, I renamed it check_for_dupid() and added more extensive comments. I repeat, it's not meant to be a substitute for new_id(). --- source/blender/blenkernel/BKE_library.h | 2 +- source/blender/blenkernel/intern/library.c | 170 +++++++++++---------- source/blender/python/api2_2x/Library.c | 21 +-- 3 files changed, 102 insertions(+), 91 deletions(-) diff --git a/source/blender/blenkernel/BKE_library.h b/source/blender/blenkernel/BKE_library.h index b0e82a3b7f7..f73c1b23a8a 100644 --- a/source/blender/blenkernel/BKE_library.h +++ b/source/blender/blenkernel/BKE_library.h @@ -47,7 +47,7 @@ void *copy_libblock(void *rt); void id_lib_extern(struct ID *id); void id_us_plus(struct ID *id); -int dup_id(struct ListBase *lb, struct ID *id, const char *name); +int check_for_dupid(struct ListBase *lb, struct ID *id, char *name); int new_id(struct ListBase *lb, struct ID *id, const char *name); struct ListBase *wich_libbase(struct Main *mainlib, short type); diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c index 4468ec684c0..2a10d44d9e6 100644 --- a/source/blender/blenkernel/intern/library.c +++ b/source/blender/blenkernel/intern/library.c @@ -788,106 +788,122 @@ static void sort_alpha_id(ListBase *lb, ID *id) } -int dup_id(ListBase *lb, ID *id, const char *tname) -/* only for local blocks: external en indirect blocks already have a unique ID */ -/* return 1: created a new name */ +/* + * Check to see if an ID name is already used, and find a new one if so. + * Return 1 if created a new name (returned in name). + * + * Normally the ID that's being check is already in the ListBase, so ID *id + * points at the new entry. The Python Library module needs to know what + * the name of a datablock will be before it is appended; in this case ID *id + * id is NULL; + */ + +int check_for_dupid(ListBase *lb, ID *id, char *name) { ID *idtest; - int nr= 0, nrtest, maxtest=32, a; - char aname[32], *name, left[32], leftest[32], in_use[32]; + int nr= 0, nrtest, a; + const int maxtest=32; + char left[32], leftest[32], in_use[32]; - /* - split name - * - search - */ + /* make sure input name is terminated properly */ + if( strlen(name) > 21 ) name[21]= 0; - if(id->lib) return 0; + while (1) { - if(tname==0) name= id->name+2; - else { - /* tname can be const */ - strncpy(aname, tname, 21); - name= aname; - - if( strlen(name) > 21 ) name[21]= 0; - } - - if(lb==NULL) lb= wich_libbase(G.main, GS(id->name)); - - /* phase 1: id already exists? */ - idtest= lb->first; - while(idtest) { - - if(id!=idtest && idtest->lib==0) { - - /* do not test alphabetic! */ - /* optimized */ - if( idtest->name[2] == name[0] ) { - if(strcmp(name, idtest->name+2)==0) break; + /* phase 1: id already exists? */ + for( idtest = lb->first; idtest; idtest = idtest->next ) { + /* if idtest is not a lib */ + if( id != idtest && idtest->lib == NULL ) { + /* do not test alphabetic! */ + /* optimized */ + if( idtest->name[2] == name[0] ) { + if(strcmp(name, idtest->name+2)==0) break; + } } } - - idtest= idtest->next; - } - /* if there is no double return */ - if(idtest==0) { - strncpy(id->name+2, name, 21); - return 0; - } - - memset(in_use, 0, maxtest); + /* if there is no double, done */ + if( idtest == NULL ) return 0; - splitIDname(name, left, &nr); - if(nr>999 && strlen(left)>16) left[16]= 0; - else if(strlen(left)>17) left[17]= 0; + /* we have a dup; need to make a new name */ + /* quick check so we can reuse one of first 32 ids if vacant */ + memset(in_use, 0, maxtest); + /* get name portion, number portion ("name.number") */ + splitIDname( name, left, &nr); - idtest= lb->first; - while(idtest) { - - if(id!=idtest && idtest->lib==0) { - - splitIDname(idtest->name+2, leftest, &nrtest); - if(strcmp(left, leftest)==0) { - - if(nrtest999 && strlen(left)>16) left[16]= 0; + else if(strlen(left)>17) left[17]= 0; + + for( idtest = lb->first; idtest; idtest = idtest->next ) { + if( id != idtest && idtest->lib == NULL ) { + splitIDname(idtest->name+2, leftest, &nrtest); + /* if base names match... */ + /* optimized */ + if( idtest->name[2] == name[0] && + strcmp(left, leftest)==0 ) { + if(nrtest < maxtest) + in_use[nrtest]= 1; /* mark as used */ + if(nr <= nrtest) + nr= nrtest+1; /* track largest unused */ + } } } - - idtest= idtest->next; - } - - for(a=0; a=nr) break; - if( in_use[a]==0 ) { - nr= a; - break; + + /* decide which value of nr to use */ + for(a=0; a=nr) break; /* stop when we've check up to biggest */ + if( in_use[a]==0 ) { /* found an unused value */ + nr = a; + break; + } } - } - - if(nr==0) strncpy(id->name+2, left, 21); - else { - if (nr >= 1000 && strlen(left) > 16) { - // this would overflow name buffer - left[16]= 0; - return (new_id(lb, id, left)); + + /* if non-numbered name was not in use, reuse it */ + if(nr==0) strcpy( name, left ); + else { + if(nr > 999 && strlen(left) > 16) { + /* this would overflow name buffer */ + left[16] = 0; + strcpy( name, left ); + continue; + } + /* this format specifier is from hell... */ + sprintf(name, "%s.%.3d", left, nr); } - /* this format specifier is from hell... */ - sprintf(id->name+2, "%s.%.3d", left, nr); + return 1; } - return 1; } +/* + * Only for local blocks: external en indirect blocks already have a + * unique ID. + * + * return 1: created a new name + */ + int new_id(ListBase *lb, ID *id, const char *tname) -/* only for local blocks: external en indirect blocks already have a unique ID */ -/* return 1: created a new name */ { int result; + char name[22]; + /* if library, don't rename */ + if(id->lib) return 0; + + /* if no libdata given, look up based on ID */ if(lb==NULL) lb= wich_libbase(G.main, GS(id->name)); - - result = dup_id( lb, id, tname ); + + if(tname==0) /* if no name given, use name of current ID */ + strncpy(name, id->name+2, 21); + else /* else make a copy (tname args can be const) */ + strncpy(name, tname, 21); + + if( strlen(name) > 21 ) name[21]= 0; + + result = check_for_dupid( lb, id, name ); + strcpy( id->name+2, name ); + if( result ) sort_alpha_id(lb, id); diff --git a/source/blender/python/api2_2x/Library.c b/source/blender/python/api2_2x/Library.c index 4251b83585d..5251f405ff5 100644 --- a/source/blender/python/api2_2x/Library.c +++ b/source/blender/python/api2_2x/Library.c @@ -570,12 +570,12 @@ PyObject *LibraryData_importLibData( BPy_LibraryData *self, char *name, int mode, Scene *scene ) { char longFilename[FILE_MAX]; - char *finalName; BlendHandle *openlib; Library *lib; LinkNode *names, *ptr; ID idtest, *id; ListBase *lb; + char newName[32]; /* try to open the library */ openlib = open_library( self->filename, longFilename ); @@ -603,16 +603,11 @@ PyObject *LibraryData_importLibData( BPy_LibraryData *self, char *name, * be renamed to. */ - if( mode == FILE_LINK ) - finalName = name; - else { /* for appends, build a fake ID block, then try to dup it */ - strncpy( idtest.name+2, name, strlen(name)+1 ); - *((short *)&idtest.name) = self->type; - idtest.newid = NULL; - idtest.lib = NULL; - dup_id( NULL, &idtest, self->name ); - finalName = idtest.name+2; - } + strncpy( newName, name, strlen(name)+1 ); + + /* for appends, see what new block will be called */ + if( mode != FILE_LINK ) + check_for_dupid( wich_libbase(G.main, self->type), NULL, newName ); /* import from the libary */ BLO_script_library_append( openlib, longFilename, name, self->type, mode, @@ -642,8 +637,8 @@ PyObject *LibraryData_importLibData( BPy_LibraryData *self, char *name, * otherwise it's NULL. */ for( id = lb->first; id; id = id->next ) { - if( id->lib == lib && id->name[2]==finalName[0] && - strcmp(id->name+2, finalName)==0 ) + if( id->lib == lib && id->name[2]==newName[0] && + strcmp(id->name+2, newName)==0 ) return GetPyObjectFromID( id ); }