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