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_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);

@ -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(nrtest<maxtest) in_use[nrtest]= 1;
if(nr <= nrtest) nr= nrtest+1;
/* if new name will be too long, truncate it */
if(nr>999 && 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<maxtest; a++) {
if(a>=nr) break;
if( in_use[a]==0 ) {
nr= a;
break;
/* 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 */
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);

@ -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 );
}