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