Revisions to previous change of new_id().
authorKen Hughes <khughes@pacific.edu>
Thu, 29 Mar 2007 04:55:29 +0000 (04:55 +0000)
committerKen Hughes <khughes@pacific.edu>
Thu, 29 Mar 2007 04:55:29 +0000 (04:55 +0000)
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
source/blender/blenkernel/intern/library.c
source/blender/python/api2_2x/Library.c

index b0e82a3b7f7bbb39dcf1acd4102794f83bd2992b..f73c1b23a8a9a3b952562428ba6fdcaa29cf8220 100644 (file)
@@ -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);
index 4468ec684c037c23308211150d44ba7112de4857..2a10d44d9e61453fc6933a287d86640929134b4b 100644 (file)
@@ -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
-        */
-
-       if(id->lib) return 0;
-
-       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;
+       /* make sure input name is terminated properly */
+       if( strlen(name) > 21 ) name[21]= 0;
+
+       while (1) {
+
+               /* 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);
-
-       splitIDname(name, left, &nr);
-       if(nr>999 && strlen(left)>16) left[16]= 0;
-       else if(strlen(left)>17) left[17]= 0;
-
-
-       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 there is no double, done */
+               if( idtest == NULL ) return 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);
+
+               /* 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);  
 
index 4251b83585d385fff7079f4724033c4f9dc9e78e..5251f405ff5f4538ec0c223c36d421c28afbb356 100644 (file)
@@ -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 );
        }