xref: /petsc/src/sys/dll/reg.c (revision 0700a8246d308f50502909ba325e6169d3ee27eb)
1 #define PETSC_DLL
2 /*
3     Provides a general mechanism to allow one to register new routines in
4     dynamic libraries for many of the PETSc objects (including, e.g., KSP and PC).
5 */
6 #include "petscsys.h"           /*I "petscsys.h" I*/
7 
8 #undef __FUNCT__
9 #define __FUNCT__ "PetscFListGetPathAndFunction"
10 PetscErrorCode PETSC_DLLEXPORT PetscFListGetPathAndFunction(const char name[],char *path[],char *function[])
11 {
12   PetscErrorCode ierr;
13   char work[PETSC_MAX_PATH_LEN],*lfunction;
14 
15   PetscFunctionBegin;
16   ierr = PetscStrncpy(work,name,256);CHKERRQ(ierr);
17   ierr = PetscStrchr(work,':',&lfunction);CHKERRQ(ierr);
18   if (lfunction != work && lfunction && lfunction[1] != ':') {
19     lfunction[0] = 0;
20     ierr = PetscStrallocpy(work,path);CHKERRQ(ierr);
21     ierr = PetscStrallocpy(lfunction+1,function);CHKERRQ(ierr);
22   } else {
23     *path = 0;
24     ierr = PetscStrallocpy(name,function);CHKERRQ(ierr);
25   }
26   PetscFunctionReturn(0);
27 }
28 
29 /*
30     This is the default list used by PETSc with the PetscDLLibrary register routines
31 */
32 PetscDLLibrary DLLibrariesLoaded = 0;
33 
34 
35 #if defined(PETSC_USE_DYNAMIC_LIBRARIES)
36 
37 #undef __FUNCT__
38 #define __FUNCT__ "PetscLoadDynamicLibrary"
39 static PetscErrorCode PETSC_DLLEXPORT PetscLoadDynamicLibrary(const char *name,PetscTruth *found)
40 {
41   char           libs[PETSC_MAX_PATH_LEN],dlib[PETSC_MAX_PATH_LEN];
42   PetscErrorCode ierr;
43 
44   PetscFunctionBegin;
45   ierr = PetscStrcpy(libs,"${PETSC_LIB_DIR}/libpetsc");CHKERRQ(ierr);
46   ierr = PetscStrcat(libs,name);CHKERRQ(ierr);
47   ierr = PetscDLLibraryRetrieve(PETSC_COMM_WORLD,libs,dlib,1024,found);CHKERRQ(ierr);
48   if (*found) {
49     ierr = PetscDLLibraryAppend(PETSC_COMM_WORLD,&DLLibrariesLoaded,dlib);CHKERRQ(ierr);
50   } else {
51     ierr = PetscStrcpy(libs,"${PETSC_DIR}/${PETSC_ARCH}/lib/libpetsc");CHKERRQ(ierr);
52     ierr = PetscStrcat(libs,name);CHKERRQ(ierr);
53     ierr = PetscDLLibraryRetrieve(PETSC_COMM_WORLD,libs,dlib,1024,found);CHKERRQ(ierr);
54     if (*found) {
55       ierr = PetscDLLibraryAppend(PETSC_COMM_WORLD,&DLLibrariesLoaded,dlib);CHKERRQ(ierr);
56     }
57   }
58   PetscFunctionReturn(0);
59 }
60 
61 #endif
62 
63 #undef __FUNCT__
64 #define __FUNCT__ "PetscInitialize_DynamicLibraries"
65 /*
66     PetscInitialize_DynamicLibraries - Adds the default dynamic link libraries to the
67     search path.
68 */
69 PetscErrorCode PETSC_DLLEXPORT PetscInitialize_DynamicLibraries(void)
70 {
71   char           *libname[32];
72   PetscErrorCode ierr;
73   PetscInt       nmax,i;
74 #if defined(PETSC_USE_DYNAMIC_LIBRARIES)
75   PetscTruth     found;
76 #endif
77   PetscFunctionBegin;
78 
79   nmax = 32;
80   ierr = PetscOptionsGetStringArray(PETSC_NULL,"-dll_prepend",libname,&nmax,PETSC_NULL);CHKERRQ(ierr);
81   for (i=0; i<nmax; i++) {
82     ierr = PetscDLLibraryPrepend(PETSC_COMM_WORLD,&DLLibrariesLoaded,libname[i]);CHKERRQ(ierr);
83     ierr = PetscFree(libname[i]);CHKERRQ(ierr);
84   }
85 
86 #if !defined(PETSC_USE_DYNAMIC_LIBRARIES)
87   /*
88       This just initializes the most basic PETSc stuff.
89 
90     The classes, from PetscDraw to PetscTS, are initialized the first
91     time an XXCreate() is called.
92   */
93   ierr = PetscInitializePackage(PETSC_NULL);CHKERRQ(ierr);
94 #else
95   ierr = PetscLoadDynamicLibrary("",&found);CHKERRQ(ierr);
96   if (!found) SETERRQ(PETSC_ERR_FILE_OPEN,"Unable to locate PETSc dynamic library \n You cannot move the dynamic libraries!");
97 #if !defined(PETSC_USE_SINGLE_LIBRARY)
98   ierr = PetscLoadDynamicLibrary("vec",&found);CHKERRQ(ierr);
99   if (!found) SETERRQ(PETSC_ERR_FILE_OPEN,"Unable to locate PETSc Vec dynamic library \n You cannot move the dynamic libraries!");
100   ierr = PetscLoadDynamicLibrary("mat",&found);CHKERRQ(ierr);
101   if (!found) SETERRQ(PETSC_ERR_FILE_OPEN,"Unable to locate PETSc Mat dynamic library \n You cannot move the dynamic libraries!");
102   ierr = PetscLoadDynamicLibrary("dm",&found);CHKERRQ(ierr);
103   if (!found) SETERRQ(PETSC_ERR_FILE_OPEN,"Unable to locate PETSc DM dynamic library \n You cannot move the dynamic libraries!");
104   ierr = PetscLoadDynamicLibrary("ksp",&found);CHKERRQ(ierr);
105   if (!found) SETERRQ(PETSC_ERR_FILE_OPEN,"Unable to locate PETSc KSP dynamic library \n You cannot move the dynamic libraries!");
106   ierr = PetscLoadDynamicLibrary("snes",&found);CHKERRQ(ierr);
107   if (!found) SETERRQ(PETSC_ERR_FILE_OPEN,"Unable to locate PETSc SNES dynamic library \n You cannot move the dynamic libraries!");
108   ierr = PetscLoadDynamicLibrary("ts",&found);CHKERRQ(ierr);
109   if (!found) SETERRQ(PETSC_ERR_FILE_OPEN,"Unable to locate PETSc TS dynamic library \n You cannot move the dynamic libraries!");
110 #endif
111 
112   ierr = PetscLoadDynamicLibrary("mesh",&found);CHKERRQ(ierr);
113   ierr = PetscLoadDynamicLibrary("contrib",&found);CHKERRQ(ierr);
114 #endif
115 
116   nmax = 32;
117   ierr = PetscOptionsGetStringArray(PETSC_NULL,"-dll_append",libname,&nmax,PETSC_NULL);CHKERRQ(ierr);
118   for (i=0; i<nmax; i++) {
119     ierr = PetscDLLibraryAppend(PETSC_COMM_WORLD,&DLLibrariesLoaded,libname[i]);CHKERRQ(ierr);
120     ierr = PetscDLLibraryCCAAppend(PETSC_COMM_WORLD,&DLLibrariesLoaded,libname[i]);CHKERRQ(ierr);
121     ierr = PetscFree(libname[i]);CHKERRQ(ierr);
122   }
123 
124   PetscFunctionReturn(0);
125 }
126 
127 #undef __FUNCT__
128 #define __FUNCT__ "PetscFinalize_DynamicLibraries"
129 /*
130      PetscFinalize_DynamicLibraries - Closes the opened dynamic libraries.
131 */
132 PetscErrorCode PetscFinalize_DynamicLibraries(void)
133 {
134   PetscErrorCode ierr;
135   PetscTruth     flg = PETSC_FALSE;
136 
137   PetscFunctionBegin;
138   ierr = PetscOptionsGetTruth(PETSC_NULL,"-dll_view",&flg,PETSC_NULL);CHKERRQ(ierr);
139   if (flg) { ierr = PetscDLLibraryPrintPath(DLLibrariesLoaded);CHKERRQ(ierr); }
140   ierr = PetscDLLibraryClose(DLLibrariesLoaded);CHKERRQ(ierr);
141   DLLibrariesLoaded = 0;
142   PetscFunctionReturn(0);
143 }
144 
145 /* ------------------------------------------------------------------------------*/
146 struct _n_PetscFList {
147   void        (*routine)(void);   /* the routine */
148   char        *path;              /* path of link library containing routine */
149   char        *name;              /* string to identify routine */
150   char        *rname;             /* routine name in dynamic library */
151   PetscFList  next;               /* next pointer */
152   PetscFList  next_list;          /* used to maintain list of all lists for freeing */
153 };
154 
155 /*
156      Keep a linked list of PetscFLists so that we can destroy all the left-over ones.
157 */
158 static PetscFList   dlallhead = 0;
159 
160 #undef __FUNCT__
161 #define __FUNCT__ "PetscFListAdd"
162 /*@C
163    PetscFListAddDynamic - Given a routine and a string id, saves that routine in the
164    specified registry.
165 
166      Not Collective
167 
168    Input Parameters:
169 +  fl    - pointer registry
170 .  name  - string to identify routine
171 .  rname - routine name in dynamic library
172 -  fnc   - function pointer (optional if using dynamic libraries)
173 
174    Notes:
175    To remove a registered routine, pass in a PETSC_NULL rname and fnc().
176 
177    Users who wish to register new classes for use by a particular PETSc
178    component (e.g., SNES) should generally call the registration routine
179    for that particular component (e.g., SNESRegisterDynamic()) instead of
180    calling PetscFListAddDynamic() directly.
181 
182    ${PETSC_ARCH}, ${PETSC_DIR}, ${PETSC_LIB_DIR}, or ${any environmental variable}
183   occuring in pathname will be replaced with appropriate values.
184 
185    Level: developer
186 
187 .seealso: PetscFListDestroy(), SNESRegisterDynamic(), KSPRegisterDynamic(),
188           PCRegisterDynamic(), TSRegisterDynamic(), PetscFList
189 @*/
190 PetscErrorCode PETSC_DLLEXPORT PetscFListAdd(PetscFList *fl,const char name[],const char rname[],void (*fnc)(void))
191 {
192   PetscFList     entry,ne;
193   PetscErrorCode ierr;
194   char           *fpath,*fname;
195 
196   PetscFunctionBegin;
197 
198   if (!*fl) {
199     ierr           = PetscNew(struct _n_PetscFList,&entry);CHKERRQ(ierr);
200     ierr           = PetscStrallocpy(name,&entry->name);CHKERRQ(ierr);
201     ierr           = PetscFListGetPathAndFunction(rname,&fpath,&fname);CHKERRQ(ierr);
202     entry->path    = fpath;
203     entry->rname   = fname;
204     entry->routine = fnc;
205     entry->next    = 0;
206     *fl = entry;
207 
208     /* add this new list to list of all lists */
209     if (!dlallhead) {
210       dlallhead        = *fl;
211       (*fl)->next_list = 0;
212     } else {
213       ne               = dlallhead;
214       dlallhead        = *fl;
215       (*fl)->next_list = ne;
216     }
217   } else {
218     /* search list to see if it is already there */
219     ne = *fl;
220     while (ne) {
221       PetscTruth founddup;
222 
223       ierr = PetscStrcmp(ne->name,name,&founddup);CHKERRQ(ierr);
224       if (founddup) { /* found duplicate */
225         ierr = PetscFListGetPathAndFunction(rname,&fpath,&fname);CHKERRQ(ierr);
226         ierr = PetscStrfree(ne->path);CHKERRQ(ierr);
227         ierr = PetscStrfree(ne->rname);CHKERRQ(ierr);
228         ne->path    = fpath;
229         ne->rname   = fname;
230         ne->routine = fnc;
231         PetscFunctionReturn(0);
232       }
233       if (ne->next) ne = ne->next; else break;
234     }
235     /* create new entry and add to end of list */
236     ierr           = PetscNew(struct _n_PetscFList,&entry);CHKERRQ(ierr);
237     ierr           = PetscStrallocpy(name,&entry->name);CHKERRQ(ierr);
238     ierr           = PetscFListGetPathAndFunction(rname,&fpath,&fname);CHKERRQ(ierr);
239     entry->path    = fpath;
240     entry->rname   = fname;
241     entry->routine = fnc;
242     entry->next    = 0;
243     ne->next       = entry;
244   }
245 
246   PetscFunctionReturn(0);
247 }
248 
249 #undef __FUNCT__
250 #define __FUNCT__ "PetscFListDestroy"
251 /*@
252     PetscFListDestroy - Destroys a list of registered routines.
253 
254     Input Parameter:
255 .   fl  - pointer to list
256 
257     Level: developer
258 
259 .seealso: PetscFListAddDynamic(), PetscFList
260 @*/
261 PetscErrorCode PETSC_DLLEXPORT PetscFListDestroy(PetscFList *fl)
262 {
263   PetscFList     next,entry,tmp = dlallhead;
264   PetscErrorCode ierr;
265 
266   PetscFunctionBegin;
267   CHKMEMQ;
268   if (!*fl) PetscFunctionReturn(0);
269 
270   if (!dlallhead) {
271     PetscFunctionReturn(0);
272   }
273 
274   /*
275        Remove this entry from the master DL list (if it is in it)
276   */
277   if (dlallhead == *fl) {
278     if (dlallhead->next_list) {
279       dlallhead = dlallhead->next_list;
280     } else {
281       dlallhead = 0;
282     }
283   } else {
284     while (tmp->next_list != *fl) {
285       tmp = tmp->next_list;
286       if (!tmp->next_list) break;
287     }
288     if (tmp->next_list) tmp->next_list = tmp->next_list->next_list;
289   }
290 
291   /* free this list */
292   entry = *fl;
293   while (entry) {
294     next = entry->next;
295     ierr = PetscStrfree(entry->path);CHKERRQ(ierr);
296     ierr = PetscFree(entry->name);CHKERRQ(ierr);
297     ierr = PetscFree(entry->rname);CHKERRQ(ierr);
298     ierr = PetscFree(entry);CHKERRQ(ierr);
299     entry = next;
300   }
301   *fl = 0;
302   PetscFunctionReturn(0);
303 }
304 
305 /*
306    Destroys all the function lists that anyone has every registered, such as KSPList, VecList, etc.
307 */
308 #undef __FUNCT__
309 #define __FUNCT__ "PetscFListDestroyAll"
310 PetscErrorCode PETSC_DLLEXPORT PetscFListDestroyAll(void)
311 {
312   PetscFList     tmp2,tmp1 = dlallhead;
313   PetscErrorCode ierr;
314 
315   PetscFunctionBegin;
316   while (tmp1) {
317     tmp2 = tmp1->next_list;
318     ierr = PetscFListDestroy(&tmp1);CHKERRQ(ierr);
319     tmp1 = tmp2;
320   }
321   dlallhead = 0;
322   PetscFunctionReturn(0);
323 }
324 
325 #undef __FUNCT__
326 #define __FUNCT__ "PetscFListFind"
327 /*@C
328     PetscFListFind - Given a name, finds the matching routine.
329 
330     Input Parameters:
331 +   fl   - pointer to list
332 .   comm - processors looking for routine
333 -   name - name string
334 
335     Output Parameters:
336 .   r - the routine
337 
338     Level: developer
339 
340 .seealso: PetscFListAddDynamic(), PetscFList
341 @*/
342 PetscErrorCode PETSC_DLLEXPORT PetscFListFind(PetscFList fl,MPI_Comm comm,const char name[],void (**r)(void))
343 {
344   PetscFList     entry = fl;
345   PetscErrorCode ierr;
346   char           *function,*path;
347 #if defined(PETSC_USE_DYNAMIC_LIBRARIES)
348   char           *newpath;
349 #endif
350   PetscTruth   flg,f1,f2,f3;
351 
352   PetscFunctionBegin;
353   if (!name) SETERRQ(PETSC_ERR_ARG_NULL,"Trying to find routine with null name");
354 
355   *r = 0;
356   ierr = PetscFListGetPathAndFunction(name,&path,&function);CHKERRQ(ierr);
357 
358   /*
359         If path then append it to search libraries
360   */
361 #if defined(PETSC_USE_DYNAMIC_LIBRARIES)
362   if (path) {
363     ierr = PetscDLLibraryAppend(comm,&DLLibrariesLoaded,path);CHKERRQ(ierr);
364   }
365 #endif
366 
367   while (entry) {
368     flg = PETSC_FALSE;
369     if (path && entry->path) {
370       ierr = PetscStrcmp(path,entry->path,&f1);CHKERRQ(ierr);
371       ierr = PetscStrcmp(function,entry->rname,&f2);CHKERRQ(ierr);
372       ierr = PetscStrcmp(function,entry->name,&f3);CHKERRQ(ierr);
373       flg =  (PetscTruth) ((f1 && f2) || (f1 && f3));
374     } else if (!path) {
375       ierr = PetscStrcmp(function,entry->name,&f1);CHKERRQ(ierr);
376       ierr = PetscStrcmp(function,entry->rname,&f2);CHKERRQ(ierr);
377       flg =  (PetscTruth) (f1 || f2);
378     } else {
379       ierr = PetscStrcmp(function,entry->name,&flg);CHKERRQ(ierr);
380       if (flg) {
381         ierr = PetscFree(function);CHKERRQ(ierr);
382         ierr = PetscStrallocpy(entry->rname,&function);CHKERRQ(ierr);
383       } else {
384         ierr = PetscStrcmp(function,entry->rname,&flg);CHKERRQ(ierr);
385       }
386     }
387 
388     if (flg) {
389 
390       if (entry->routine) {
391         *r   = entry->routine;
392         ierr = PetscStrfree(path);CHKERRQ(ierr);
393         ierr = PetscFree(function);CHKERRQ(ierr);
394         PetscFunctionReturn(0);
395       }
396 
397       if ((path && entry->path && f3) || (!path && f1)) { /* convert name of function (alias) to actual function name */
398         ierr = PetscFree(function);CHKERRQ(ierr);
399         ierr = PetscStrallocpy(entry->rname,&function);CHKERRQ(ierr);
400       }
401 
402       /* it is not yet in memory so load from dynamic library */
403 #if defined(PETSC_USE_DYNAMIC_LIBRARIES)
404       newpath = path;
405       if (!path) newpath = entry->path;
406       ierr = PetscDLLibrarySym(comm,&DLLibrariesLoaded,newpath,entry->rname,(void **)r);CHKERRQ(ierr);
407       if (*r) {
408         entry->routine = *r;
409         ierr = PetscStrfree(path);CHKERRQ(ierr);
410         ierr = PetscFree(function);CHKERRQ(ierr);
411         PetscFunctionReturn(0);
412       } else {
413         PetscErrorPrintf("Unable to find function. Search path:\n");
414         ierr = PetscDLLibraryPrintPath(DLLibrariesLoaded);CHKERRQ(ierr);
415         SETERRQ1(PETSC_ERR_PLIB,"Unable to find function:%s: either it is mis-spelled or dynamic library is not in path",entry->rname);
416       }
417 #endif
418     }
419     entry = entry->next;
420   }
421 
422 #if defined(PETSC_USE_DYNAMIC_LIBRARIES)
423   /* Function never registered; try for it anyway */
424   ierr = PetscDLLibrarySym(comm,&DLLibrariesLoaded,path,function,(void **)r);CHKERRQ(ierr);
425   ierr = PetscStrfree(path);CHKERRQ(ierr);
426   if (*r) {
427     ierr = PetscFListAdd(&fl,name,name,*r);CHKERRQ(ierr);
428   }
429 #endif
430   ierr = PetscFree(function);CHKERRQ(ierr);
431   PetscFunctionReturn(0);
432 }
433 
434 #undef __FUNCT__
435 #define __FUNCT__ "PetscFListView"
436 /*@
437    PetscFListView - prints out contents of an PetscFList
438 
439    Collective over MPI_Comm
440 
441    Input Parameters:
442 +  list - the list of functions
443 -  viewer - currently ignored
444 
445    Level: developer
446 
447 .seealso: PetscFListAddDynamic(), PetscFListPrintTypes(), PetscFList
448 @*/
449 PetscErrorCode PETSC_DLLEXPORT PetscFListView(PetscFList list,PetscViewer viewer)
450 {
451   PetscErrorCode ierr;
452   PetscTruth     iascii;
453 
454   PetscFunctionBegin;
455   if (!viewer) viewer = PETSC_VIEWER_STDOUT_SELF;
456   PetscValidPointer(list,1);
457   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,2);
458 
459   ierr = PetscTypeCompare((PetscObject)viewer,PETSC_VIEWER_ASCII,&iascii);CHKERRQ(ierr);
460   if (!iascii) SETERRQ(PETSC_ERR_SUP,"Only ASCII viewer supported");
461 
462   while (list) {
463     if (list->path) {
464       ierr = PetscViewerASCIIPrintf(viewer," %s %s %s\n",list->path,list->name,list->rname);CHKERRQ(ierr);
465     } else {
466       ierr = PetscViewerASCIIPrintf(viewer," %s %s\n",list->name,list->rname);CHKERRQ(ierr);
467     }
468     list = list->next;
469   }
470   ierr = PetscViewerASCIIPrintf(viewer,"\n");CHKERRQ(ierr);
471   PetscFunctionReturn(0);
472 }
473 
474 #undef __FUNCT__
475 #define __FUNCT__ "PetscFListGet"
476 /*@
477    PetscFListGet - Gets an array the contains the entries in PetscFList, this is used
478          by help etc.
479 
480    Collective over MPI_Comm
481 
482    Input Parameter:
483 .  list   - list of types
484 
485    Output Parameter:
486 +  array - array of names
487 -  n - length of array
488 
489    Notes:
490        This allocates the array so that must be freed. BUT the individual entries are
491     not copied so should not be freed.
492 
493    Level: developer
494 
495 .seealso: PetscFListAddDynamic(), PetscFList
496 @*/
497 PetscErrorCode PETSC_DLLEXPORT PetscFListGet(PetscFList list,char ***array,int *n)
498 {
499   PetscErrorCode ierr;
500   PetscInt       count = 0;
501   PetscFList     klist = list;
502 
503   PetscFunctionBegin;
504   while (list) {
505     list = list->next;
506     count++;
507   }
508   ierr  = PetscMalloc((count+1)*sizeof(char *),array);CHKERRQ(ierr);
509   count = 0;
510   while (klist) {
511     (*array)[count] = klist->name;
512     klist = klist->next;
513     count++;
514   }
515   (*array)[count] = 0;
516   *n = count+1;
517   PetscFunctionReturn(0);
518 }
519 
520 
521 #undef __FUNCT__
522 #define __FUNCT__ "PetscFListPrintTypes"
523 /*@C
524    PetscFListPrintTypes - Prints the methods available.
525 
526    Collective over MPI_Comm
527 
528    Input Parameters:
529 +  comm   - the communicator (usually MPI_COMM_WORLD)
530 .  fd     - file to print to, usually stdout
531 .  prefix - prefix to prepend to name (optional)
532 .  name   - option string (for example, "-ksp_type")
533 .  text - short description of the object (for example, "Krylov solvers")
534 .  man - name of manual page that discusses the object (for example, "KSPCreate")
535 .  list   - list of types
536 -  def - default (current) value
537 
538    Level: developer
539 
540 .seealso: PetscFListAddDynamic(), PetscFList
541 @*/
542 PetscErrorCode PETSC_DLLEXPORT PetscFListPrintTypes(MPI_Comm comm,FILE *fd,const char prefix[],const char name[],const char text[],const char man[],PetscFList list,const char def[])
543 {
544   PetscErrorCode ierr;
545   PetscInt       count = 0;
546   char           p[64];
547 
548   PetscFunctionBegin;
549   if (!fd) fd = PETSC_STDOUT;
550 
551   ierr = PetscStrcpy(p,"-");CHKERRQ(ierr);
552   if (prefix) {ierr = PetscStrcat(p,prefix);CHKERRQ(ierr);}
553   ierr = PetscFPrintf(comm,fd,"  %s%s <%s>: %s (one of)",p,name+1,def,text);CHKERRQ(ierr);
554 
555   while (list) {
556     ierr = PetscFPrintf(comm,fd," %s",list->name);CHKERRQ(ierr);
557     list = list->next;
558     count++;
559     if (count == 8) {ierr = PetscFPrintf(comm,fd,"\n     ");CHKERRQ(ierr);}
560   }
561   ierr = PetscFPrintf(comm,fd," (%s)\n",man);CHKERRQ(ierr);
562   PetscFunctionReturn(0);
563 }
564 
565 #undef __FUNCT__
566 #define __FUNCT__ "PetscFListDuplicate"
567 /*@
568     PetscFListDuplicate - Creates a new list from a given object list.
569 
570     Input Parameters:
571 .   fl   - pointer to list
572 
573     Output Parameters:
574 .   nl - the new list (should point to 0 to start, otherwise appends)
575 
576     Level: developer
577 
578 .seealso: PetscFList, PetscFListAdd(), PetscFlistDestroy()
579 
580 @*/
581 PetscErrorCode PETSC_DLLEXPORT PetscFListDuplicate(PetscFList fl,PetscFList *nl)
582 {
583   PetscErrorCode ierr;
584   char           path[PETSC_MAX_PATH_LEN];
585 
586   PetscFunctionBegin;
587   while (fl) {
588     /* this is silly, rebuild the complete pathname */
589     if (fl->path) {
590       ierr = PetscStrcpy(path,fl->path);CHKERRQ(ierr);
591       ierr = PetscStrcat(path,":");CHKERRQ(ierr);
592       ierr = PetscStrcat(path,fl->name);CHKERRQ(ierr);
593     } else {
594       ierr = PetscStrcpy(path,fl->name);CHKERRQ(ierr);
595     }
596     ierr = PetscFListAdd(nl,path,fl->rname,fl->routine);CHKERRQ(ierr);
597     fl   = fl->next;
598   }
599   PetscFunctionReturn(0);
600 }
601 
602 
603 #undef __FUNCT__
604 #define __FUNCT__ "PetscFListConcat"
605 /*
606     PetscFListConcat - joins name of a libary, and the path where it is located
607     into a single string.
608 
609     Input Parameters:
610 .   path   - path to the library name.
611 .   name   - name of the library
612 
613     Output Parameters:
614 .   fullname - the name that is the union of the path and the library name,
615                delimited by a semicolon, i.e., path:name
616 
617     Notes:
618     If the path is NULL, assumes that the name, specified also includes
619     the path as path:name
620 
621 */
622 PetscErrorCode PETSC_DLLEXPORT PetscFListConcat(const char path[],const char name[],char fullname[])
623 {
624   PetscErrorCode ierr;
625   PetscFunctionBegin;
626   if (path) {
627     ierr = PetscStrcpy(fullname,path);CHKERRQ(ierr);
628     ierr = PetscStrcat(fullname,":");CHKERRQ(ierr);
629     ierr = PetscStrcat(fullname,name);CHKERRQ(ierr);
630   } else {
631     ierr = PetscStrcpy(fullname,name);CHKERRQ(ierr);
632   }
633   PetscFunctionReturn(0);
634 }
635