xref: /petsc/src/sys/fileio/mprint.c (revision d781fa04b676d21af57f7756ed6a18cab633cde7)
1 /*
2       Utilites routines to add simple ASCII IO capability.
3 */
4 #include <../src/sys/fileio/mprint.h>
5 #include <errno.h>
6 /*
7    If petsc_history is on, then all Petsc*Printf() results are saved
8    if the appropriate (usually .petschistory) file.
9 */
10 extern FILE *petsc_history;
11 /*
12      Allows one to overwrite where standard out is sent. For example
13      PETSC_STDOUT = fopen("/dev/ttyXX","w") will cause all standard out
14      writes to go to terminal XX; assuming you have write permission there
15 */
16 FILE *PETSC_STDOUT = 0;
17 /*
18      Allows one to overwrite where standard error is sent. For example
19      PETSC_STDERR = fopen("/dev/ttyXX","w") will cause all standard error
20      writes to go to terminal XX; assuming you have write permission there
21 */
22 FILE *PETSC_STDERR = 0;
23 
24 /*@C
25      PetscFormatConvertGetSize - Gets the length of a string needed to hold format converted with PetscFormatConvert()
26 
27    Input Parameter:
28 .   format - the PETSc format string
29 
30    Output Parameter:
31 .   size - the needed length of the new format
32 
33  Level: developer
34 
35 .seealso: PetscFormatConvert(), PetscVSNPrintf(), PetscVFPrintf()
36 
37 @*/
38 PetscErrorCode PetscFormatConvertGetSize(const char *format,size_t *size)
39 {
40   PetscInt i = 0;
41 
42   PetscFunctionBegin;
43   *size = 0;
44   while (format[i]) {
45     if (format[i] == '%' && format[i+1] == '%') {
46       i++; i++; *size += 2;
47     } else if (format[i] == '%') {
48       /* Find the letter */
49       for (; format[i] && format[i] <= '9'; i++,(*size += 1));
50       switch (format[i]) {
51       case 'D':
52 #if defined(PETSC_USE_64BIT_INDICES)
53         *size += 2;
54 #endif
55         break;
56       case 'g':
57         *size += 4;
58         break;
59       default:
60         break;
61       }
62       *size += 1;
63       i++;
64     } else {
65       i++;
66       *size += 1;
67     }
68   }
69   *size += 1; /* space for NULL character */
70   PetscFunctionReturn(0);
71 }
72 
73 /*@C
74      PetscFormatConvert - Takes a PETSc format string and converts the %D to %d for 32 bit PETSc indices and %lld for 64 bit PETSc indices. Also
75                         converts %g to [|%g|] so that PetscVSNPrintf() can easily insure all %g formatted numbers have a decimal point when printed.
76 
77    Input Parameters:
78 +   format - the PETSc format string
79 .   newformat - the location to put the new format
80 -   size - the length of newformat, you can use PetscFormatConvertGetSize() to compute the needed size
81 
82     Note: this exists so we can have the same code when PetscInt is either int or long long int
83 
84  Level: developer
85 
86 .seealso: PetscFormatConvertGetSize(), PetscVSNPrintf(), PetscVFPrintf()
87 
88 @*/
89 PetscErrorCode PetscFormatConvert(const char *format,char *newformat)
90 {
91   PetscInt i = 0, j = 0;
92 
93   PetscFunctionBegin;
94   while (format[i]) {
95     if (format[i] == '%' && format[i+1] == '%') {
96       newformat[j++] = format[i++];
97       newformat[j++] = format[i++];
98     } else if (format[i] == '%') {
99       if (format[i+1] == 'g') {
100         newformat[j++] = '[';
101         newformat[j++] = '|';
102       }
103       /* Find the letter */
104       for (; format[i] && format[i] <= '9'; i++) newformat[j++] = format[i];
105       switch (format[i]) {
106       case 'D':
107 #if !defined(PETSC_USE_64BIT_INDICES)
108         newformat[j++] = 'd';
109 #else
110         newformat[j++] = 'l';
111         newformat[j++] = 'l';
112         newformat[j++] = 'd';
113 #endif
114         break;
115       case 'g':
116         newformat[j++] = format[i];
117         if (format[i-1] == '%') {
118           newformat[j++] = '|';
119           newformat[j++] = ']';
120         }
121         break;
122       case 'G':
123         SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"%%G format is no longer supported, use %%g and cast the argument to double");
124         break;
125       case 'F':
126         SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"%%F format is no longer supported, use %%f and cast the argument to double");
127         break;
128       default:
129         newformat[j++] = format[i];
130         break;
131       }
132       i++;
133     } else newformat[j++] = format[i++];
134   }
135   newformat[j] = 0;
136   PetscFunctionReturn(0);
137 }
138 
139 #define PETSCVSNPRINTFDEFAULTFORMATBUFFERSIZE 8*1024
140 
141 /*@C
142      PetscVSNPrintf - The PETSc version of vsnprintf(). Converts a PETSc format string into a standard C format string and then puts all the
143        function arguments into a string using the format statement.
144 
145    Input Parameters:
146 +   str - location to put result
147 .   len - the amount of space in str
148 +   format - the PETSc format string
149 -   fullLength - the amount of space in str actually used.
150 
151     Developer Notes: this function may be called from an error handler, if an error occurs when it is called by the error handler than likely
152       a recursion will occur and possible crash.
153 
154  Level: developer
155 
156 .seealso: PetscVSNPrintf(), PetscErrorPrintf(), PetscVPrintf()
157 
158 @*/
159 PetscErrorCode PetscVSNPrintf(char *str,size_t len,const char *format,size_t *fullLength,va_list Argp)
160 {
161   char           *newformat = NULL;
162   char           formatbuf[PETSCVSNPRINTFDEFAULTFORMATBUFFERSIZE];
163   size_t         newLength;
164   PetscErrorCode ierr;
165 
166   PetscFunctionBegin;
167   ierr = PetscFormatConvertGetSize(format,&newLength);CHKERRQ(ierr);
168   if (newLength < PETSCVSNPRINTFDEFAULTFORMATBUFFERSIZE) {
169     newformat = formatbuf;
170     newLength = PETSCVSNPRINTFDEFAULTFORMATBUFFERSIZE-1;
171   } else {
172     ierr      = PetscMalloc1(newLength, &newformat);CHKERRQ(ierr);
173   }
174   ierr = PetscFormatConvert(format,newformat);CHKERRQ(ierr);
175 #if defined(PETSC_HAVE_VSNPRINTF_CHAR)
176   (void) vsnprintf(str,len,newformat,(char*)Argp);
177 #elif defined(PETSC_HAVE_VSNPRINTF)
178   (void) vsnprintf(str,len,newformat,Argp);
179 #elif defined(PETSC_HAVE__VSNPRINTF)
180   (void) _vsnprintf(str,len,newformat,Argp);
181 #else
182 #error "vsnprintf not found"
183 #endif
184   if (newLength > PETSCVSNPRINTFDEFAULTFORMATBUFFERSIZE-1) {
185     ierr = PetscFree(newformat);CHKERRQ(ierr);
186   }
187   {
188     PetscBool foundedot;
189     size_t cnt = 0,ncnt = 0,leng;
190     ierr = PetscStrlen(str,&leng);CHKERRQ(ierr);
191     if (leng > 4) {
192       for (cnt=0; cnt<leng-4; cnt++) {
193         if (str[cnt] == '[' && str[cnt+1] == '|'){
194            cnt++; cnt++;
195            foundedot = PETSC_FALSE;
196            for (; cnt<leng-1; cnt++) {
197              if (str[cnt] == '|' && str[cnt+1] == ']'){
198                cnt++;
199                if (!foundedot) str[ncnt++] = '.';
200                ncnt--;
201                break;
202              } else {
203                if (str[cnt] == 'e' || str[cnt] == '.') foundedot = PETSC_TRUE;
204                str[ncnt++] = str[cnt];
205              }
206            }
207         } else {
208           str[ncnt] = str[cnt];
209         }
210         ncnt++;
211       }
212       while (cnt < leng) {
213         str[ncnt] = str[cnt]; ncnt++; cnt++;
214       }
215       str[ncnt] = 0;
216     }
217   }
218 #if defined(PETSC_HAVE_WINDOWS_H) && !defined(PETSC_HAVE__SET_OUTPUT_FORMAT)
219   /* older Windows OS always produces e-+0np for floating point output; remove the extra 0 */
220   {
221     size_t cnt = 0,ncnt = 0,leng;
222     ierr = PetscStrlen(str,&leng);CHKERRQ(ierr);
223     if (leng > 5) {
224       for (cnt=0; cnt<leng-4; cnt++) {
225         if (str[cnt] == 'e' && (str[cnt+1] == '-' || str[cnt+1] == '+') && str[cnt+2] == '0'  && str[cnt+3] >= '0' && str[cnt+3] <= '9' && str[cnt+4] >= '0' && str[cnt+4] <= '9') {
226           str[ncnt] = str[cnt]; ncnt++; cnt++;
227           str[ncnt] = str[cnt]; ncnt++; cnt++; cnt++;
228           str[ncnt] = str[cnt];
229         } else {
230           str[ncnt] = str[cnt];
231         }
232         ncnt++;
233       }
234       while (cnt < leng) {
235         str[ncnt] = str[cnt]; ncnt++; cnt++;
236       }
237       str[ncnt] = 0;
238     }
239   }
240 #endif
241   if (fullLength) {
242     ierr = PetscStrlen(str,fullLength);CHKERRQ(ierr);
243   }
244   PetscFunctionReturn(0);
245 }
246 
247 /*@C
248      PetscVFPrintf -  All PETSc standard out and error messages are sent through this function; so, in theory, this can
249         can be replaced with something that does not simply write to a file.
250 
251       To use, write your own function for example,
252 $PetscErrorCode mypetscvfprintf(FILE *fd,const char format[],va_list Argp)
253 ${
254 $  PetscErrorCode ierr;
255 $
256 $  PetscFunctionBegin;
257 $   if (fd != stdout && fd != stderr) {  handle regular files
258 $      ierr = PetscVFPrintfDefault(fd,format,Argp);CHKERR(ierr);
259 $  } else {
260 $     char   buff[BIG];
261 $     size_t length;
262 $     ierr = PetscVSNPrintf(buff,BIG,format,&length,Argp);CHKERRQ(ierr);
263 $     now send buff to whatever stream or whatever you want
264 $ }
265 $ PetscFunctionReturn(0);
266 $}
267 then before the call to PetscInitialize() do the assignment
268 $    PetscVFPrintf = mypetscvfprintf;
269 
270       Notes: For error messages this may be called by any process, for regular standard out it is
271           called only by process 0 of a given communicator
272 
273       Developer Notes: this could be called by an error handler, if that happens then a recursion of the error handler may occur
274                        and a crash
275 
276   Level:  developer
277 
278 .seealso: PetscVSNPrintf(), PetscErrorPrintf()
279 
280 @*/
281 PetscErrorCode PetscVFPrintfDefault(FILE *fd,const char *format,va_list Argp)
282 {
283   char           str[8*1024];
284   PetscErrorCode ierr;
285 
286   PetscFunctionBegin;
287   ierr = PetscVSNPrintf(str,sizeof(str),format,NULL,Argp);CHKERRQ(ierr);
288   fprintf(fd,"%s",str);CHKERRQ(ierr);
289   fflush(fd);
290   PetscFunctionReturn(0);
291 }
292 
293 /*@C
294     PetscSNPrintf - Prints to a string of given length
295 
296     Not Collective
297 
298     Input Parameters:
299 +   str - the string to print to
300 .   len - the length of str
301 .   format - the usual printf() format string
302 -   any arguments
303 
304    Level: intermediate
305 
306 .seealso: PetscSynchronizedFlush(), PetscSynchronizedFPrintf(), PetscFPrintf(), PetscVSNPrintf(),
307           PetscPrintf(), PetscViewerASCIIPrintf(), PetscViewerASCIISynchronizedPrintf(), PetscVFPrintf()
308 @*/
309 PetscErrorCode PetscSNPrintf(char *str,size_t len,const char format[],...)
310 {
311   PetscErrorCode ierr;
312   size_t         fullLength;
313   va_list        Argp;
314 
315   PetscFunctionBegin;
316   va_start(Argp,format);
317   ierr = PetscVSNPrintf(str,len,format,&fullLength,Argp);CHKERRQ(ierr);
318   PetscFunctionReturn(0);
319 }
320 
321 /*@C
322     PetscSNPrintfCount - Prints to a string of given length, returns count
323 
324     Not Collective
325 
326     Input Parameters:
327 +   str - the string to print to
328 .   len - the length of str
329 .   format - the usual printf() format string
330 .   countused - number of characters used
331 -   any arguments
332 
333    Level: intermediate
334 
335 .seealso: PetscSynchronizedFlush(), PetscSynchronizedFPrintf(), PetscFPrintf(), PetscVSNPrintf(),
336           PetscPrintf(), PetscViewerASCIIPrintf(), PetscViewerASCIISynchronizedPrintf(), PetscSNPrintf(), PetscVFPrintf()
337 @*/
338 PetscErrorCode PetscSNPrintfCount(char *str,size_t len,const char format[],size_t *countused,...)
339 {
340   PetscErrorCode ierr;
341   va_list        Argp;
342 
343   PetscFunctionBegin;
344   va_start(Argp,countused);
345   ierr = PetscVSNPrintf(str,len,format,countused,Argp);CHKERRQ(ierr);
346   PetscFunctionReturn(0);
347 }
348 
349 /* ----------------------------------------------------------------------- */
350 
351 PrintfQueue petsc_printfqueue       = 0,petsc_printfqueuebase = 0;
352 int         petsc_printfqueuelength = 0;
353 
354 /*@C
355     PetscSynchronizedPrintf - Prints synchronized output from several processors.
356     Output of the first processor is followed by that of the second, etc.
357 
358     Not Collective
359 
360     Input Parameters:
361 +   comm - the communicator
362 -   format - the usual printf() format string
363 
364    Level: intermediate
365 
366     Notes:
367     REQUIRES a call to PetscSynchronizedFlush() by all the processes after the completion of the calls to PetscSynchronizedPrintf() for the information
368     from all the processors to be printed.
369 
370     Fortran Note:
371     The call sequence is PetscSynchronizedPrintf(MPI_Comm, character(*), PetscErrorCode ierr) from Fortran.
372     That is, you can only pass a single character string from Fortran.
373 
374 .seealso: PetscSynchronizedFlush(), PetscSynchronizedFPrintf(), PetscFPrintf(),
375           PetscPrintf(), PetscViewerASCIIPrintf(), PetscViewerASCIISynchronizedPrintf()
376 @*/
377 PetscErrorCode PetscSynchronizedPrintf(MPI_Comm comm,const char format[],...)
378 {
379   PetscErrorCode ierr;
380   PetscMPIInt    rank;
381 
382   PetscFunctionBegin;
383   if (comm == MPI_COMM_NULL) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Called with MPI_COMM_NULL, likely PetscObjectComm() failed");
384   ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
385 
386   /* First processor prints immediately to stdout */
387   if (!rank) {
388     va_list Argp;
389     va_start(Argp,format);
390     ierr = (*PetscVFPrintf)(PETSC_STDOUT,format,Argp);CHKERRQ(ierr);
391     if (petsc_history) {
392       va_start(Argp,format);
393       ierr = (*PetscVFPrintf)(petsc_history,format,Argp);CHKERRQ(ierr);
394     }
395     va_end(Argp);
396   } else { /* other processors add to local queue */
397     va_list     Argp;
398     PrintfQueue next;
399     size_t      fullLength = 8191;
400 
401     ierr = PetscNew(&next);CHKERRQ(ierr);
402     if (petsc_printfqueue) {
403       petsc_printfqueue->next = next;
404       petsc_printfqueue       = next;
405       petsc_printfqueue->next = 0;
406     } else petsc_printfqueuebase = petsc_printfqueue = next;
407     petsc_printfqueuelength++;
408     next->size = -1;
409     while ((PetscInt)fullLength >= next->size) {
410       next->size = fullLength+1;
411 
412       ierr = PetscMalloc1(next->size, &next->string);CHKERRQ(ierr);
413       va_start(Argp,format);
414       ierr = PetscMemzero(next->string,next->size);CHKERRQ(ierr);
415       ierr = PetscVSNPrintf(next->string,next->size,format, &fullLength,Argp);CHKERRQ(ierr);
416       va_end(Argp);
417     }
418   }
419   PetscFunctionReturn(0);
420 }
421 
422 /*@C
423     PetscSynchronizedFPrintf - Prints synchronized output to the specified file from
424     several processors.  Output of the first processor is followed by that of the
425     second, etc.
426 
427     Not Collective
428 
429     Input Parameters:
430 +   comm - the communicator
431 .   fd - the file pointer
432 -   format - the usual printf() format string
433 
434     Level: intermediate
435 
436     Notes:
437     REQUIRES a intervening call to PetscSynchronizedFlush() for the information
438     from all the processors to be printed.
439 
440 .seealso: PetscSynchronizedPrintf(), PetscSynchronizedFlush(), PetscFPrintf(),
441           PetscFOpen(), PetscViewerASCIISynchronizedPrintf(), PetscViewerASCIIPrintf()
442 
443 @*/
444 PetscErrorCode PetscSynchronizedFPrintf(MPI_Comm comm,FILE *fp,const char format[],...)
445 {
446   PetscErrorCode ierr;
447   PetscMPIInt    rank;
448 
449   PetscFunctionBegin;
450   if (comm == MPI_COMM_NULL) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Called with MPI_COMM_NULL, likely PetscObjectComm() failed");
451   ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
452 
453   /* First processor prints immediately to fp */
454   if (!rank) {
455     va_list Argp;
456     va_start(Argp,format);
457     ierr = (*PetscVFPrintf)(fp,format,Argp);CHKERRQ(ierr);
458     if (petsc_history && (fp !=petsc_history)) {
459       va_start(Argp,format);
460       ierr = (*PetscVFPrintf)(petsc_history,format,Argp);CHKERRQ(ierr);
461     }
462     va_end(Argp);
463   } else { /* other processors add to local queue */
464     va_list     Argp;
465     PrintfQueue next;
466     size_t      fullLength = 8191;
467     ierr = PetscNew(&next);CHKERRQ(ierr);
468     if (petsc_printfqueue) {
469       petsc_printfqueue->next = next;
470       petsc_printfqueue       = next;
471       petsc_printfqueue->next = 0;
472     } else petsc_printfqueuebase = petsc_printfqueue = next;
473     petsc_printfqueuelength++;
474     next->size = -1;
475     while ((PetscInt)fullLength >= next->size) {
476       next->size = fullLength+1;
477       ierr = PetscMalloc1(next->size, &next->string);CHKERRQ(ierr);
478       va_start(Argp,format);
479       ierr = PetscMemzero(next->string,next->size);CHKERRQ(ierr);
480       ierr = PetscVSNPrintf(next->string,next->size,format,&fullLength,Argp);CHKERRQ(ierr);
481       va_end(Argp);
482     }
483   }
484   PetscFunctionReturn(0);
485 }
486 
487 /*@C
488     PetscSynchronizedFlush - Flushes to the screen output from all processors
489     involved in previous PetscSynchronizedPrintf()/PetscSynchronizedFPrintf() calls.
490 
491     Collective on MPI_Comm
492 
493     Input Parameters:
494 +   comm - the communicator
495 -   fd - the file pointer (valid on process 0 of the communicator)
496 
497     Level: intermediate
498 
499     Notes:
500     If PetscSynchronizedPrintf() and/or PetscSynchronizedFPrintf() are called with
501     different MPI communicators there must be an intervening call to PetscSynchronizedFlush() between the calls with different MPI communicators.
502 
503     From Fortran pass PETSC_STDOUT if the flush is for standard out; otherwise pass a value obtained from PetscFOpen()
504 
505 .seealso: PetscSynchronizedPrintf(), PetscFPrintf(), PetscPrintf(), PetscViewerASCIIPrintf(),
506           PetscViewerASCIISynchronizedPrintf()
507 @*/
508 PetscErrorCode PetscSynchronizedFlush(MPI_Comm comm,FILE *fd)
509 {
510   PetscErrorCode ierr;
511   PetscMPIInt    rank,size,tag,i,j,n = 0,dummy = 0;
512   char          *message;
513   MPI_Status     status;
514 
515   PetscFunctionBegin;
516   ierr = PetscCommDuplicate(comm,&comm,&tag);CHKERRQ(ierr);
517   ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
518   ierr = MPI_Comm_size(comm,&size);CHKERRQ(ierr);
519 
520   /* First processor waits for messages from all other processors */
521   if (!rank) {
522     if (!fd) fd = PETSC_STDOUT;
523     for (i=1; i<size; i++) {
524       /* to prevent a flood of messages to process zero, request each message separately */
525       ierr = MPI_Send(&dummy,1,MPI_INT,i,tag,comm);CHKERRQ(ierr);
526       ierr = MPI_Recv(&n,1,MPI_INT,i,tag,comm,&status);CHKERRQ(ierr);
527       for (j=0; j<n; j++) {
528         PetscMPIInt size = 0;
529 
530         ierr = MPI_Recv(&size,1,MPI_INT,i,tag,comm,&status);CHKERRQ(ierr);
531         ierr = PetscMalloc1(size, &message);CHKERRQ(ierr);
532         ierr = MPI_Recv(message,size,MPI_CHAR,i,tag,comm,&status);CHKERRQ(ierr);
533         ierr = PetscFPrintf(comm,fd,"%s",message);CHKERRQ(ierr);
534         ierr = PetscFree(message);CHKERRQ(ierr);
535       }
536     }
537   } else { /* other processors send queue to processor 0 */
538     PrintfQueue next = petsc_printfqueuebase,previous;
539 
540     ierr = MPI_Recv(&dummy,1,MPI_INT,0,tag,comm,&status);CHKERRQ(ierr);
541     ierr = MPI_Send(&petsc_printfqueuelength,1,MPI_INT,0,tag,comm);CHKERRQ(ierr);
542     for (i=0; i<petsc_printfqueuelength; i++) {
543       ierr     = MPI_Send(&next->size,1,MPI_INT,0,tag,comm);CHKERRQ(ierr);
544       ierr     = MPI_Send(next->string,next->size,MPI_CHAR,0,tag,comm);CHKERRQ(ierr);
545       previous = next;
546       next     = next->next;
547       ierr     = PetscFree(previous->string);CHKERRQ(ierr);
548       ierr     = PetscFree(previous);CHKERRQ(ierr);
549     }
550     petsc_printfqueue       = 0;
551     petsc_printfqueuelength = 0;
552   }
553   ierr = PetscCommDestroy(&comm);CHKERRQ(ierr);
554   PetscFunctionReturn(0);
555 }
556 
557 /* ---------------------------------------------------------------------------------------*/
558 
559 /*@C
560     PetscFPrintf - Prints to a file, only from the first
561     processor in the communicator.
562 
563     Not Collective
564 
565     Input Parameters:
566 +   comm - the communicator
567 .   fd - the file pointer
568 -   format - the usual printf() format string
569 
570     Level: intermediate
571 
572     Fortran Note:
573     This routine is not supported in Fortran.
574 
575    Concepts: printing^in parallel
576    Concepts: printf^in parallel
577 
578 .seealso: PetscPrintf(), PetscSynchronizedPrintf(), PetscViewerASCIIPrintf(),
579           PetscViewerASCIISynchronizedPrintf(), PetscSynchronizedFlush()
580 @*/
581 PetscErrorCode PetscFPrintf(MPI_Comm comm,FILE* fd,const char format[],...)
582 {
583   PetscErrorCode ierr;
584   PetscMPIInt    rank;
585 
586   PetscFunctionBegin;
587   if (comm == MPI_COMM_NULL) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Called with MPI_COMM_NULL, likely PetscObjectComm() failed");
588   ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
589   if (!rank) {
590     va_list Argp;
591     va_start(Argp,format);
592     ierr = (*PetscVFPrintf)(fd,format,Argp);CHKERRQ(ierr);
593     if (petsc_history && (fd !=petsc_history)) {
594       va_start(Argp,format);
595       ierr = (*PetscVFPrintf)(petsc_history,format,Argp);CHKERRQ(ierr);
596     }
597     va_end(Argp);
598   }
599   PetscFunctionReturn(0);
600 }
601 
602 /*@C
603     PetscPrintf - Prints to standard out, only from the first
604     processor in the communicator. Calls from other processes are ignored.
605 
606     Not Collective
607 
608     Input Parameters:
609 +   comm - the communicator
610 -   format - the usual printf() format string
611 
612    Level: intermediate
613 
614     Fortran Note:
615     The call sequence is PetscPrintf(MPI_Comm, character(*), PetscErrorCode ierr) from Fortran.
616     That is, you can only pass a single character string from Fortran.
617 
618    Concepts: printing^in parallel
619    Concepts: printf^in parallel
620 
621 .seealso: PetscFPrintf(), PetscSynchronizedPrintf()
622 @*/
623 PetscErrorCode PetscPrintf(MPI_Comm comm,const char format[],...)
624 {
625   PetscErrorCode ierr;
626   PetscMPIInt    rank;
627 
628   PetscFunctionBegin;
629   if (comm == MPI_COMM_NULL) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Called with MPI_COMM_NULL, likely PetscObjectComm() failed");
630   ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
631   if (!rank) {
632     va_list Argp;
633     va_start(Argp,format);
634     ierr = (*PetscVFPrintf)(PETSC_STDOUT,format,Argp);CHKERRQ(ierr);
635     if (petsc_history) {
636       va_start(Argp,format);
637       ierr = (*PetscVFPrintf)(petsc_history,format,Argp);CHKERRQ(ierr);
638     }
639     va_end(Argp);
640   }
641   PetscFunctionReturn(0);
642 }
643 
644 /* ---------------------------------------------------------------------------------------*/
645 /*@C
646      PetscHelpPrintf -  All PETSc help messages are passing through this function. You can change how help messages are printed by
647         replacinng it  with something that does not simply write to a stdout.
648 
649       To use, write your own function for example,
650 $PetscErrorCode mypetschelpprintf(MPI_Comm comm,const char format[],....)
651 ${
652 $ PetscFunctionReturn(0);
653 $}
654 then before the call to PetscInitialize() do the assignment
655 $    PetscHelpPrintf = mypetschelpprintf;
656 
657   Note: the default routine used is called PetscHelpPrintfDefault().
658 
659   Level:  developer
660 
661 .seealso: PetscVSNPrintf(), PetscVFPrintf(), PetscErrorPrintf()
662 @*/
663 PetscErrorCode PetscHelpPrintfDefault(MPI_Comm comm,const char format[],...)
664 {
665   PetscErrorCode ierr;
666   PetscMPIInt    rank;
667 
668   PetscFunctionBegin;
669   if (comm == MPI_COMM_NULL) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Called with MPI_COMM_NULL, likely PetscObjectComm() failed");
670   ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
671   if (!rank) {
672     va_list Argp;
673     va_start(Argp,format);
674     ierr = (*PetscVFPrintf)(PETSC_STDOUT,format,Argp);CHKERRQ(ierr);
675     if (petsc_history) {
676       va_start(Argp,format);
677       ierr = (*PetscVFPrintf)(petsc_history,format,Argp);CHKERRQ(ierr);
678     }
679     va_end(Argp);
680   }
681   PetscFunctionReturn(0);
682 }
683 
684 /* ---------------------------------------------------------------------------------------*/
685 
686 
687 /*@C
688     PetscSynchronizedFGets - Several processors all get the same line from a file.
689 
690     Collective on MPI_Comm
691 
692     Input Parameters:
693 +   comm - the communicator
694 .   fd - the file pointer
695 -   len - the length of the output buffer
696 
697     Output Parameter:
698 .   string - the line read from the file, at end of file string[0] == 0
699 
700     Level: intermediate
701 
702 .seealso: PetscSynchronizedPrintf(), PetscSynchronizedFlush(),
703           PetscFOpen(), PetscViewerASCIISynchronizedPrintf(), PetscViewerASCIIPrintf()
704 
705 @*/
706 PetscErrorCode PetscSynchronizedFGets(MPI_Comm comm,FILE *fp,size_t len,char string[])
707 {
708   PetscErrorCode ierr;
709   PetscMPIInt    rank;
710 
711   PetscFunctionBegin;
712   ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
713 
714   if (!rank) {
715     char *ptr = fgets(string, len, fp);
716 
717     if (!ptr) {
718       string[0] = 0;
719       if (!feof(fp)) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_FILE_READ, "Error reading from file: %d", errno);
720     }
721   }
722   ierr = MPI_Bcast(string,len,MPI_BYTE,0,comm);CHKERRQ(ierr);
723   PetscFunctionReturn(0);
724 }
725 
726 #if defined(PETSC_HAVE_CLOSURES)
727 int (^SwiftClosure)(const char*) = 0;
728 
729 PetscErrorCode PetscVFPrintfToString(FILE *fd,const char format[],va_list Argp)
730 {
731   PetscErrorCode ierr;
732 
733   PetscFunctionBegin;
734   if (fd != stdout && fd != stderr) { /* handle regular files */
735     ierr = PetscVFPrintfDefault(fd,format,Argp);CHKERRQ(ierr);
736   } else {
737     size_t len=8*1024,length;
738     char   buf[len];
739 
740     ierr = PetscVSNPrintf(buf,len,format,&length,Argp);CHKERRQ(ierr);
741     ierr = SwiftClosure(buf);CHKERRQ(ierr);
742   }
743   PetscFunctionReturn(0);
744 }
745 
746 /*
747    Provide a Swift function that processes all the PETSc calls to PetscVFPrintf()
748 */
749 PetscErrorCode PetscVFPrintfSetClosure(int (^closure)(const char*))
750 {
751   PetscVFPrintf = PetscVFPrintfToString;
752   SwiftClosure  = closure;
753   return 0;
754 }
755 #endif
756 
757 #if defined(PETSC_HAVE_MATLAB_ENGINE)
758 #include <mex.h>
759 PetscErrorCode PetscVFPrintf_Matlab(FILE *fd,const char format[],va_list Argp)
760 {
761   PetscErrorCode ierr;
762 
763   PetscFunctionBegin;
764   if (fd != stdout && fd != stderr) { /* handle regular files */
765     ierr = PetscVFPrintfDefault(fd,format,Argp);CHKERRQ(ierr);
766   } else {
767     size_t len=8*1024,length;
768     char   buf[len];
769 
770     ierr = PetscVSNPrintf(buf,len,format,&length,Argp);CHKERRQ(ierr);
771     mexPrintf("%s",buf);
772   }
773   PetscFunctionReturn(0);
774 }
775 #endif
776 
777 /*@C
778      PetscFormatStrip - Takes a PETSc format string and removes all numerical modifiers to % operations
779 
780    Input Parameters:
781 .   format - the PETSc format string
782 
783  Level: developer
784 
785 @*/
786 PetscErrorCode PetscFormatStrip(char *format)
787 {
788   size_t loc1 = 0, loc2 = 0;
789 
790   PetscFunctionBegin;
791   while (format[loc2]) {
792     if (format[loc2] == '%') {
793       format[loc1++] = format[loc2++];
794       while (format[loc2] && ((format[loc2] >= '0' && format[loc2] <= '9') || format[loc2] == '.')) loc2++;
795     }
796     format[loc1++] = format[loc2++];
797   }
798   PetscFunctionReturn(0);
799 }
800 
801