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().
This commit is contained in:
Ken Hughes 2007-03-29 04:55:29 +00:00
parent 42fa2ba00b
commit b8e425af7c
3 changed files with 102 additions and 91 deletions

@ -47,7 +47,7 @@ void *copy_libblock(void *rt);
void id_lib_extern(struct ID *id); void id_lib_extern(struct ID *id);
void id_us_plus(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); int new_id(struct ListBase *lb, struct ID *id, const char *name);
struct ListBase *wich_libbase(struct Main *mainlib, short type); struct ListBase *wich_libbase(struct Main *mainlib, short type);

@ -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 */ * Check to see if an ID name is already used, and find a new one if so.
/* return 1: created a new name */ * 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; ID *idtest;
int nr= 0, nrtest, maxtest=32, a; int nr= 0, nrtest, a;
char aname[32], *name, left[32], leftest[32], in_use[32]; const int maxtest=32;
char left[32], leftest[32], in_use[32];
/* - split name /* make sure input name is terminated properly */
* - search if( strlen(name) > 21 ) name[21]= 0;
*/
if(id->lib) return 0; while (1) {
if(tname==0) name= id->name+2; /* phase 1: id already exists? */
else { for( idtest = lb->first; idtest; idtest = idtest->next ) {
/* tname can be const */ /* if idtest is not a lib */
strncpy(aname, tname, 21); if( id != idtest && idtest->lib == NULL ) {
name= aname; /* do not test alphabetic! */
/* optimized */
if( strlen(name) > 21 ) name[21]= 0; if( idtest->name[2] == name[0] ) {
} if(strcmp(name, idtest->name+2)==0) break;
}
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;
} }
} }
idtest= idtest->next; /* if there is no double, done */
} if( idtest == NULL ) return 0;
/* if there is no double return */ /* we have a dup; need to make a new name */
if(idtest==0) { /* quick check so we can reuse one of first 32 ids if vacant */
strncpy(id->name+2, name, 21); memset(in_use, 0, maxtest);
return 0;
}
memset(in_use, 0, maxtest); /* get name portion, number portion ("name.number") */
splitIDname( name, left, &nr);
splitIDname(name, left, &nr); /* if new name will be too long, truncate it */
if(nr>999 && strlen(left)>16) left[16]= 0; if(nr>999 && strlen(left)>16) left[16]= 0;
else if(strlen(left)>17) left[17]= 0; else if(strlen(left)>17) left[17]= 0;
for( idtest = lb->first; idtest; idtest = idtest->next ) {
idtest= lb->first; if( id != idtest && idtest->lib == NULL ) {
while(idtest) { splitIDname(idtest->name+2, leftest, &nrtest);
/* if base names match... */
if(id!=idtest && idtest->lib==0) { /* optimized */
if( idtest->name[2] == name[0] &&
splitIDname(idtest->name+2, leftest, &nrtest); strcmp(left, leftest)==0 ) {
if(strcmp(left, leftest)==0) { if(nrtest < maxtest)
in_use[nrtest]= 1; /* mark as used */
if(nrtest<maxtest) in_use[nrtest]= 1; if(nr <= nrtest)
if(nr <= nrtest) nr= nrtest+1; nr= nrtest+1; /* track largest unused */
}
} }
} }
idtest= idtest->next; /* decide which value of nr to use */
} for(a=0; a<maxtest; a++) {
if(a>=nr) break; /* stop when we've check up to biggest */
for(a=0; a<maxtest; a++) { if( in_use[a]==0 ) { /* found an unused value */
if(a>=nr) break; nr = a;
if( in_use[a]==0 ) { break;
nr= a; }
break;
} }
}
if(nr==0) strncpy(id->name+2, left, 21); /* if non-numbered name was not in use, reuse it */
else { if(nr==0) strcpy( name, left );
if (nr >= 1000 && strlen(left) > 16) { else {
// this would overflow name buffer if(nr > 999 && strlen(left) > 16) {
left[16]= 0; /* this would overflow name buffer */
return (new_id(lb, id, left)); 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... */ return 1;
sprintf(id->name+2, "%s.%.3d", left, nr);
} }
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) 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; 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)); 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 ) if( result )
sort_alpha_id(lb, id); sort_alpha_id(lb, id);

@ -570,12 +570,12 @@ PyObject *LibraryData_importLibData( BPy_LibraryData *self, char *name,
int mode, Scene *scene ) int mode, Scene *scene )
{ {
char longFilename[FILE_MAX]; char longFilename[FILE_MAX];
char *finalName;
BlendHandle *openlib; BlendHandle *openlib;
Library *lib; Library *lib;
LinkNode *names, *ptr; LinkNode *names, *ptr;
ID idtest, *id; ID idtest, *id;
ListBase *lb; ListBase *lb;
char newName[32];
/* try to open the library */ /* try to open the library */
openlib = open_library( self->filename, longFilename ); openlib = open_library( self->filename, longFilename );
@ -603,16 +603,11 @@ PyObject *LibraryData_importLibData( BPy_LibraryData *self, char *name,
* be renamed to. * be renamed to.
*/ */
if( mode == FILE_LINK ) strncpy( newName, name, strlen(name)+1 );
finalName = name;
else { /* for appends, build a fake ID block, then try to dup it */ /* for appends, see what new block will be called */
strncpy( idtest.name+2, name, strlen(name)+1 ); if( mode != FILE_LINK )
*((short *)&idtest.name) = self->type; check_for_dupid( wich_libbase(G.main, self->type), NULL, newName );
idtest.newid = NULL;
idtest.lib = NULL;
dup_id( NULL, &idtest, self->name );
finalName = idtest.name+2;
}
/* import from the libary */ /* import from the libary */
BLO_script_library_append( openlib, longFilename, name, self->type, mode, 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. * otherwise it's NULL.
*/ */
for( id = lb->first; id; id = id->next ) { for( id = lb->first; id; id = id->next ) {
if( id->lib == lib && id->name[2]==finalName[0] && if( id->lib == lib && id->name[2]==newName[0] &&
strcmp(id->name+2, finalName)==0 ) strcmp(id->name+2, newName)==0 )
return GetPyObjectFromID( id ); return GetPyObjectFromID( id );
} }