xref: /petsc/src/sys/fileio/mprint.c (revision e42d1bb89c832af7cff7ca5dc681a50206c18b0f)
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 PETSCDEFAULTBUFFERSIZE 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:
152     this function may be called from an error handler, if an error occurs when it is called by the error handler than likely
153       a recursion will occur and possible crash.
154 
155  Level: developer
156 
157 .seealso: PetscVSNPrintf(), PetscErrorPrintf(), PetscVPrintf()
158 
159 @*/
160 PetscErrorCode PetscVSNPrintf(char *str,size_t len,const char *format,size_t *fullLength,va_list Argp)
161 {
162   char           *newformat = NULL;
163   char           formatbuf[PETSCDEFAULTBUFFERSIZE];
164   size_t         newLength;
165   PetscErrorCode ierr;
166   int            flen;
167 
168   PetscFunctionBegin;
169   ierr = PetscFormatConvertGetSize(format,&newLength);CHKERRQ(ierr);
170   if (newLength < PETSCDEFAULTBUFFERSIZE) {
171     newformat = formatbuf;
172     newLength = PETSCDEFAULTBUFFERSIZE-1;
173   } else {
174     ierr      = PetscMalloc1(newLength, &newformat);CHKERRQ(ierr);
175   }
176   ierr = PetscFormatConvert(format,newformat);CHKERRQ(ierr);
177 #if defined(PETSC_HAVE_VSNPRINTF)
178   flen = vsnprintf(str,len,newformat,Argp);
179 #else
180 #error "vsnprintf not found"
181 #endif
182   if (fullLength) *fullLength = 1 + (size_t) flen;
183   if (newLength > PETSCDEFAULTBUFFERSIZE-1) {
184     ierr = PetscFree(newformat);CHKERRQ(ierr);
185   }
186   {
187     PetscBool foundedot;
188     size_t cnt = 0,ncnt = 0,leng;
189     ierr = PetscStrlen(str,&leng);CHKERRQ(ierr);
190     if (leng > 4) {
191       for (cnt=0; cnt<leng-4; cnt++) {
192         if (str[cnt] == '[' && str[cnt+1] == '|'){
193            cnt++; cnt++;
194            foundedot = PETSC_FALSE;
195            for (; cnt<leng-1; cnt++) {
196              if (str[cnt] == '|' && str[cnt+1] == ']'){
197                cnt++;
198                if (!foundedot) str[ncnt++] = '.';
199                ncnt--;
200                break;
201              } else {
202                if (str[cnt] == 'e' || str[cnt] == '.') foundedot = PETSC_TRUE;
203                str[ncnt++] = str[cnt];
204              }
205            }
206         } else {
207           str[ncnt] = str[cnt];
208         }
209         ncnt++;
210       }
211       while (cnt < leng) {
212         str[ncnt] = str[cnt]; ncnt++; cnt++;
213       }
214       str[ncnt] = 0;
215     }
216   }
217 #if defined(PETSC_HAVE_WINDOWS_H) && !defined(PETSC_HAVE__SET_OUTPUT_FORMAT)
218   /* older Windows OS always produces e-+0np for floating point output; remove the extra 0 */
219   {
220     size_t cnt = 0,ncnt = 0,leng;
221     ierr = PetscStrlen(str,&leng);CHKERRQ(ierr);
222     if (leng > 5) {
223       for (cnt=0; cnt<leng-4; cnt++) {
224         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') {
225           str[ncnt] = str[cnt]; ncnt++; cnt++;
226           str[ncnt] = str[cnt]; ncnt++; cnt++; cnt++;
227           str[ncnt] = str[cnt];
228         } else {
229           str[ncnt] = str[cnt];
230         }
231         ncnt++;
232       }
233       while (cnt < leng) {
234         str[ncnt] = str[cnt]; ncnt++; cnt++;
235       }
236       str[ncnt] = 0;
237     }
238   }
239 #endif
240   PetscFunctionReturn(0);
241 }
242 
243 /*@C
244      PetscVFPrintf -  All PETSc standard out and error messages are sent through this function; so, in theory, this can
245         can be replaced with something that does not simply write to a file.
246 
247       To use, write your own function for example,
248 $PetscErrorCode mypetscvfprintf(FILE *fd,const char format[],va_list Argp)
249 ${
250 $  PetscErrorCode ierr;
251 $
252 $  PetscFunctionBegin;
253 $   if (fd != stdout && fd != stderr) {  handle regular files
254 $      ierr = PetscVFPrintfDefault(fd,format,Argp);CHKERR(ierr);
255 $  } else {
256 $     char   buff[BIG];
257 $     size_t length;
258 $     ierr = PetscVSNPrintf(buff,BIG,format,&length,Argp);CHKERRQ(ierr);
259 $     now send buff to whatever stream or whatever you want
260 $ }
261 $ PetscFunctionReturn(0);
262 $}
263 then before the call to PetscInitialize() do the assignment
264 $    PetscVFPrintf = mypetscvfprintf;
265 
266       Notes:
267     For error messages this may be called by any process, for regular standard out it is
268           called only by process 0 of a given communicator
269 
270       Developer Notes:
271     this could be called by an error handler, if that happens then a recursion of the error handler may occur
272                        and a crash
273 
274   Level:  developer
275 
276 .seealso: PetscVSNPrintf(), PetscErrorPrintf()
277 
278 @*/
279 PetscErrorCode PetscVFPrintfDefault(FILE *fd,const char *format,va_list Argp)
280 {
281   char           str[PETSCDEFAULTBUFFERSIZE];
282   char           *buff = str;
283   size_t         fullLength;
284   PetscErrorCode ierr;
285 #if defined(PETSC_HAVE_VA_COPY)
286   va_list        Argpcopy;
287 #endif
288 
289   PetscFunctionBegin;
290 #if defined(PETSC_HAVE_VA_COPY)
291   va_copy(Argpcopy,Argp);
292 #endif
293   ierr = PetscVSNPrintf(str,sizeof(str),format,&fullLength,Argp);CHKERRQ(ierr);
294   if (fullLength > sizeof(str)) {
295     ierr = PetscMalloc1(fullLength,&buff);CHKERRQ(ierr);
296 #if defined(PETSC_HAVE_VA_COPY)
297     ierr = PetscVSNPrintf(buff,fullLength,format,NULL,Argpcopy);CHKERRQ(ierr);
298 #else
299     SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"C89 does not support va_copy() hence cannot print long strings with PETSc printing routines");
300 #endif
301   }
302   fprintf(fd,"%s",buff);CHKERRQ(ierr);
303   fflush(fd);
304   if (buff != str) {
305     ierr = PetscFree(buff);CHKERRQ(ierr);
306   }
307   PetscFunctionReturn(0);
308 }
309 
310 /*@C
311     PetscSNPrintf - Prints to a string of given length
312 
313     Not Collective
314 
315     Input Parameters:
316 +   str - the string to print to
317 .   len - the length of str
318 .   format - the usual printf() format string
319 -   any arguments
320 
321    Level: intermediate
322 
323 .seealso: PetscSynchronizedFlush(), PetscSynchronizedFPrintf(), PetscFPrintf(), PetscVSNPrintf(),
324           PetscPrintf(), PetscViewerASCIIPrintf(), PetscViewerASCIISynchronizedPrintf(), PetscVFPrintf()
325 @*/
326 PetscErrorCode PetscSNPrintf(char *str,size_t len,const char format[],...)
327 {
328   PetscErrorCode ierr;
329   size_t         fullLength;
330   va_list        Argp;
331 
332   PetscFunctionBegin;
333   va_start(Argp,format);
334   ierr = PetscVSNPrintf(str,len,format,&fullLength,Argp);CHKERRQ(ierr);
335   PetscFunctionReturn(0);
336 }
337 
338 /*@C
339     PetscSNPrintfCount - Prints to a string of given length, returns count
340 
341     Not Collective
342 
343     Input Parameters:
344 +   str - the string to print to
345 .   len - the length of str
346 .   format - the usual printf() format string
347 -   any arguments
348 
349     Output Parameter:
350 .   countused - number of characters used
351 
352    Level: intermediate
353 
354 .seealso: PetscSynchronizedFlush(), PetscSynchronizedFPrintf(), PetscFPrintf(), PetscVSNPrintf(),
355           PetscPrintf(), PetscViewerASCIIPrintf(), PetscViewerASCIISynchronizedPrintf(), PetscSNPrintf(), PetscVFPrintf()
356 @*/
357 PetscErrorCode PetscSNPrintfCount(char *str,size_t len,const char format[],size_t *countused,...)
358 {
359   PetscErrorCode ierr;
360   va_list        Argp;
361 
362   PetscFunctionBegin;
363   va_start(Argp,countused);
364   ierr = PetscVSNPrintf(str,len,format,countused,Argp);CHKERRQ(ierr);
365   PetscFunctionReturn(0);
366 }
367 
368 /* ----------------------------------------------------------------------- */
369 
370 PrintfQueue petsc_printfqueue       = 0,petsc_printfqueuebase = 0;
371 int         petsc_printfqueuelength = 0;
372 
373 /*@C
374     PetscSynchronizedPrintf - Prints synchronized output from several processors.
375     Output of the first processor is followed by that of the second, etc.
376 
377     Not Collective
378 
379     Input Parameters:
380 +   comm - the communicator
381 -   format - the usual printf() format string
382 
383    Level: intermediate
384 
385     Notes:
386     REQUIRES a call to PetscSynchronizedFlush() by all the processes after the completion of the calls to PetscSynchronizedPrintf() for the information
387     from all the processors to be printed.
388 
389     Fortran Note:
390     The call sequence is PetscSynchronizedPrintf(MPI_Comm, character(*), PetscErrorCode ierr) from Fortran.
391     That is, you can only pass a single character string from Fortran.
392 
393 .seealso: PetscSynchronizedFlush(), PetscSynchronizedFPrintf(), PetscFPrintf(),
394           PetscPrintf(), PetscViewerASCIIPrintf(), PetscViewerASCIISynchronizedPrintf()
395 @*/
396 PetscErrorCode PetscSynchronizedPrintf(MPI_Comm comm,const char format[],...)
397 {
398   PetscErrorCode ierr;
399   PetscMPIInt    rank;
400 
401   PetscFunctionBegin;
402   if (comm == MPI_COMM_NULL) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Called with MPI_COMM_NULL, likely PetscObjectComm() failed");
403   ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
404 
405   /* First processor prints immediately to stdout */
406   if (!rank) {
407     va_list Argp;
408     va_start(Argp,format);
409     ierr = (*PetscVFPrintf)(PETSC_STDOUT,format,Argp);CHKERRQ(ierr);
410     if (petsc_history) {
411       va_start(Argp,format);
412       ierr = (*PetscVFPrintf)(petsc_history,format,Argp);CHKERRQ(ierr);
413     }
414     va_end(Argp);
415   } else { /* other processors add to local queue */
416     va_list     Argp;
417     PrintfQueue next;
418     size_t      fullLength = PETSCDEFAULTBUFFERSIZE;
419 
420     ierr = PetscNew(&next);CHKERRQ(ierr);
421     if (petsc_printfqueue) {
422       petsc_printfqueue->next = next;
423       petsc_printfqueue       = next;
424       petsc_printfqueue->next = 0;
425     } else petsc_printfqueuebase = petsc_printfqueue = next;
426     petsc_printfqueuelength++;
427     next->size   = -1;
428     next->string = NULL;
429     while ((PetscInt)fullLength >= next->size) {
430       next->size = fullLength+1;
431       ierr = PetscFree(next->string);CHKERRQ(ierr);
432       ierr = PetscMalloc1(next->size, &next->string);CHKERRQ(ierr);
433       va_start(Argp,format);
434       ierr = PetscMemzero(next->string,next->size);CHKERRQ(ierr);
435       ierr = PetscVSNPrintf(next->string,next->size,format, &fullLength,Argp);CHKERRQ(ierr);
436       va_end(Argp);
437     }
438   }
439   PetscFunctionReturn(0);
440 }
441 
442 /*@C
443     PetscSynchronizedFPrintf - Prints synchronized output to the specified file from
444     several processors.  Output of the first processor is followed by that of the
445     second, etc.
446 
447     Not Collective
448 
449     Input Parameters:
450 +   comm - the communicator
451 .   fd - the file pointer
452 -   format - the usual printf() format string
453 
454     Level: intermediate
455 
456     Notes:
457     REQUIRES a intervening call to PetscSynchronizedFlush() for the information
458     from all the processors to be printed.
459 
460 .seealso: PetscSynchronizedPrintf(), PetscSynchronizedFlush(), PetscFPrintf(),
461           PetscFOpen(), PetscViewerASCIISynchronizedPrintf(), PetscViewerASCIIPrintf()
462 
463 @*/
464 PetscErrorCode PetscSynchronizedFPrintf(MPI_Comm comm,FILE *fp,const char format[],...)
465 {
466   PetscErrorCode ierr;
467   PetscMPIInt    rank;
468 
469   PetscFunctionBegin;
470   if (comm == MPI_COMM_NULL) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Called with MPI_COMM_NULL, likely PetscObjectComm() failed");
471   ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
472 
473   /* First processor prints immediately to fp */
474   if (!rank) {
475     va_list Argp;
476     va_start(Argp,format);
477     ierr = (*PetscVFPrintf)(fp,format,Argp);CHKERRQ(ierr);
478     if (petsc_history && (fp !=petsc_history)) {
479       va_start(Argp,format);
480       ierr = (*PetscVFPrintf)(petsc_history,format,Argp);CHKERRQ(ierr);
481     }
482     va_end(Argp);
483   } else { /* other processors add to local queue */
484     va_list     Argp;
485     PrintfQueue next;
486     size_t      fullLength = PETSCDEFAULTBUFFERSIZE;
487 
488     ierr = PetscNew(&next);CHKERRQ(ierr);
489     if (petsc_printfqueue) {
490       petsc_printfqueue->next = next;
491       petsc_printfqueue       = next;
492       petsc_printfqueue->next = 0;
493     } else petsc_printfqueuebase = petsc_printfqueue = next;
494     petsc_printfqueuelength++;
495     next->size   = -1;
496     next->string = NULL;
497     while ((PetscInt)fullLength >= next->size) {
498       next->size = fullLength+1;
499       ierr = PetscFree(next->string);CHKERRQ(ierr);
500       ierr = PetscMalloc1(next->size, &next->string);CHKERRQ(ierr);
501       va_start(Argp,format);
502       ierr = PetscMemzero(next->string,next->size);CHKERRQ(ierr);
503       ierr = PetscVSNPrintf(next->string,next->size,format,&fullLength,Argp);CHKERRQ(ierr);
504       va_end(Argp);
505     }
506   }
507   PetscFunctionReturn(0);
508 }
509 
510 /*@C
511     PetscSynchronizedFlush - Flushes to the screen output from all processors
512     involved in previous PetscSynchronizedPrintf()/PetscSynchronizedFPrintf() calls.
513 
514     Collective on MPI_Comm
515 
516     Input Parameters:
517 +   comm - the communicator
518 -   fd - the file pointer (valid on process 0 of the communicator)
519 
520     Level: intermediate
521 
522     Notes:
523     If PetscSynchronizedPrintf() and/or PetscSynchronizedFPrintf() are called with
524     different MPI communicators there must be an intervening call to PetscSynchronizedFlush() between the calls with different MPI communicators.
525 
526     From Fortran pass PETSC_STDOUT if the flush is for standard out; otherwise pass a value obtained from PetscFOpen()
527 
528 .seealso: PetscSynchronizedPrintf(), PetscFPrintf(), PetscPrintf(), PetscViewerASCIIPrintf(),
529           PetscViewerASCIISynchronizedPrintf()
530 @*/
531 PetscErrorCode PetscSynchronizedFlush(MPI_Comm comm,FILE *fd)
532 {
533   PetscErrorCode ierr;
534   PetscMPIInt    rank,size,tag,i,j,n = 0,dummy = 0;
535   char          *message;
536   MPI_Status     status;
537 
538   PetscFunctionBegin;
539   ierr = PetscCommDuplicate(comm,&comm,&tag);CHKERRQ(ierr);
540   ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
541   ierr = MPI_Comm_size(comm,&size);CHKERRQ(ierr);
542 
543   /* First processor waits for messages from all other processors */
544   if (!rank) {
545     if (!fd) fd = PETSC_STDOUT;
546     for (i=1; i<size; i++) {
547       /* to prevent a flood of messages to process zero, request each message separately */
548       ierr = MPI_Send(&dummy,1,MPI_INT,i,tag,comm);CHKERRQ(ierr);
549       ierr = MPI_Recv(&n,1,MPI_INT,i,tag,comm,&status);CHKERRQ(ierr);
550       for (j=0; j<n; j++) {
551         PetscMPIInt size = 0;
552 
553         ierr = MPI_Recv(&size,1,MPI_INT,i,tag,comm,&status);CHKERRQ(ierr);
554         ierr = PetscMalloc1(size, &message);CHKERRQ(ierr);
555         ierr = MPI_Recv(message,size,MPI_CHAR,i,tag,comm,&status);CHKERRQ(ierr);
556         ierr = PetscFPrintf(comm,fd,"%s",message);CHKERRQ(ierr);
557         ierr = PetscFree(message);CHKERRQ(ierr);
558       }
559     }
560   } else { /* other processors send queue to processor 0 */
561     PrintfQueue next = petsc_printfqueuebase,previous;
562 
563     ierr = MPI_Recv(&dummy,1,MPI_INT,0,tag,comm,&status);CHKERRQ(ierr);
564     ierr = MPI_Send(&petsc_printfqueuelength,1,MPI_INT,0,tag,comm);CHKERRQ(ierr);
565     for (i=0; i<petsc_printfqueuelength; i++) {
566       ierr     = MPI_Send(&next->size,1,MPI_INT,0,tag,comm);CHKERRQ(ierr);
567       ierr     = MPI_Send(next->string,next->size,MPI_CHAR,0,tag,comm);CHKERRQ(ierr);
568       previous = next;
569       next     = next->next;
570       ierr     = PetscFree(previous->string);CHKERRQ(ierr);
571       ierr     = PetscFree(previous);CHKERRQ(ierr);
572     }
573     petsc_printfqueue       = 0;
574     petsc_printfqueuelength = 0;
575   }
576   ierr = PetscCommDestroy(&comm);CHKERRQ(ierr);
577   PetscFunctionReturn(0);
578 }
579 
580 /* ---------------------------------------------------------------------------------------*/
581 
582 /*@C
583     PetscFPrintf - Prints to a file, only from the first
584     processor in the communicator.
585 
586     Not Collective
587 
588     Input Parameters:
589 +   comm - the communicator
590 .   fd - the file pointer
591 -   format - the usual printf() format string
592 
593     Level: intermediate
594 
595     Fortran Note:
596     This routine is not supported in Fortran.
597 
598    Concepts: printing^in parallel
599    Concepts: printf^in parallel
600 
601 .seealso: PetscPrintf(), PetscSynchronizedPrintf(), PetscViewerASCIIPrintf(),
602           PetscViewerASCIISynchronizedPrintf(), PetscSynchronizedFlush()
603 @*/
604 PetscErrorCode PetscFPrintf(MPI_Comm comm,FILE* fd,const char format[],...)
605 {
606   PetscErrorCode ierr;
607   PetscMPIInt    rank;
608 
609   PetscFunctionBegin;
610   if (comm == MPI_COMM_NULL) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Called with MPI_COMM_NULL, likely PetscObjectComm() failed");
611   ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
612   if (!rank) {
613     va_list Argp;
614     va_start(Argp,format);
615     ierr = (*PetscVFPrintf)(fd,format,Argp);CHKERRQ(ierr);
616     if (petsc_history && (fd !=petsc_history)) {
617       va_start(Argp,format);
618       ierr = (*PetscVFPrintf)(petsc_history,format,Argp);CHKERRQ(ierr);
619     }
620     va_end(Argp);
621   }
622   PetscFunctionReturn(0);
623 }
624 
625 /*@C
626     PetscPrintf - Prints to standard out, only from the first
627     processor in the communicator. Calls from other processes are ignored.
628 
629     Not Collective
630 
631     Input Parameters:
632 +   comm - the communicator
633 -   format - the usual printf() format string
634 
635    Level: intermediate
636 
637     Fortran Note:
638     The call sequence is PetscPrintf(MPI_Comm, character(*), PetscErrorCode ierr) from Fortran.
639     That is, you can only pass a single character string from Fortran.
640 
641    Concepts: printing^in parallel
642    Concepts: printf^in parallel
643 
644 .seealso: PetscFPrintf(), PetscSynchronizedPrintf()
645 @*/
646 PetscErrorCode PetscPrintf(MPI_Comm comm,const char format[],...)
647 {
648   PetscErrorCode ierr;
649   PetscMPIInt    rank;
650 
651   PetscFunctionBegin;
652   if (comm == MPI_COMM_NULL) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Called with MPI_COMM_NULL, likely PetscObjectComm() failed");
653   ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
654   if (!rank) {
655     va_list Argp;
656     va_start(Argp,format);
657     ierr = (*PetscVFPrintf)(PETSC_STDOUT,format,Argp);CHKERRQ(ierr);
658     if (petsc_history) {
659       va_start(Argp,format);
660       ierr = (*PetscVFPrintf)(petsc_history,format,Argp);CHKERRQ(ierr);
661     }
662     va_end(Argp);
663   }
664   PetscFunctionReturn(0);
665 }
666 
667 /* ---------------------------------------------------------------------------------------*/
668 /*@C
669      PetscHelpPrintf -  All PETSc help messages are passing through this function. You can change how help messages are printed by
670         replacinng it  with something that does not simply write to a stdout.
671 
672       To use, write your own function for example,
673 $PetscErrorCode mypetschelpprintf(MPI_Comm comm,const char format[],....)
674 ${
675 $ PetscFunctionReturn(0);
676 $}
677 then before the call to PetscInitialize() do the assignment
678 $    PetscHelpPrintf = mypetschelpprintf;
679 
680   Note: the default routine used is called PetscHelpPrintfDefault().
681 
682   Level:  developer
683 
684 .seealso: PetscVSNPrintf(), PetscVFPrintf(), PetscErrorPrintf()
685 @*/
686 PetscErrorCode PetscHelpPrintfDefault(MPI_Comm comm,const char format[],...)
687 {
688   PetscErrorCode ierr;
689   PetscMPIInt    rank;
690 
691   PetscFunctionBegin;
692   if (comm == MPI_COMM_NULL) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Called with MPI_COMM_NULL, likely PetscObjectComm() failed");
693   ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
694   if (!rank) {
695     va_list Argp;
696     va_start(Argp,format);
697     ierr = (*PetscVFPrintf)(PETSC_STDOUT,format,Argp);CHKERRQ(ierr);
698     if (petsc_history) {
699       va_start(Argp,format);
700       ierr = (*PetscVFPrintf)(petsc_history,format,Argp);CHKERRQ(ierr);
701     }
702     va_end(Argp);
703   }
704   PetscFunctionReturn(0);
705 }
706 
707 /* ---------------------------------------------------------------------------------------*/
708 
709 
710 /*@C
711     PetscSynchronizedFGets - Several processors all get the same line from a file.
712 
713     Collective on MPI_Comm
714 
715     Input Parameters:
716 +   comm - the communicator
717 .   fd - the file pointer
718 -   len - the length of the output buffer
719 
720     Output Parameter:
721 .   string - the line read from the file, at end of file string[0] == 0
722 
723     Level: intermediate
724 
725 .seealso: PetscSynchronizedPrintf(), PetscSynchronizedFlush(),
726           PetscFOpen(), PetscViewerASCIISynchronizedPrintf(), PetscViewerASCIIPrintf()
727 
728 @*/
729 PetscErrorCode PetscSynchronizedFGets(MPI_Comm comm,FILE *fp,size_t len,char string[])
730 {
731   PetscErrorCode ierr;
732   PetscMPIInt    rank;
733 
734   PetscFunctionBegin;
735   ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
736 
737   if (!rank) {
738     char *ptr = fgets(string, len, fp);
739 
740     if (!ptr) {
741       string[0] = 0;
742       if (!feof(fp)) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_FILE_READ, "Error reading from file: %d", errno);
743     }
744   }
745   ierr = MPI_Bcast(string,len,MPI_BYTE,0,comm);CHKERRQ(ierr);
746   PetscFunctionReturn(0);
747 }
748 
749 #if defined(PETSC_HAVE_CLOSURES)
750 int (^SwiftClosure)(const char*) = 0;
751 
752 PetscErrorCode PetscVFPrintfToString(FILE *fd,const char format[],va_list Argp)
753 {
754   PetscErrorCode ierr;
755 
756   PetscFunctionBegin;
757   if (fd != stdout && fd != stderr) { /* handle regular files */
758     ierr = PetscVFPrintfDefault(fd,format,Argp);CHKERRQ(ierr);
759   } else {
760     size_t length;
761     char   buff[PETSCDEFAULTBUFFERSIZE];
762 
763     ierr = PetscVSNPrintf(buf,size(buff),format,&length,Argp);CHKERRQ(ierr);
764     ierr = SwiftClosure(buff);CHKERRQ(ierr);
765   }
766   PetscFunctionReturn(0);
767 }
768 
769 /*
770    Provide a Swift function that processes all the PETSc calls to PetscVFPrintf()
771 */
772 PetscErrorCode PetscVFPrintfSetClosure(int (^closure)(const char*))
773 {
774   PetscVFPrintf = PetscVFPrintfToString;
775   SwiftClosure  = closure;
776   return 0;
777 }
778 #endif
779 
780 #if defined(PETSC_HAVE_MATLAB_ENGINE)
781 #include <mex.h>
782 PetscErrorCode PetscVFPrintf_Matlab(FILE *fd,const char format[],va_list Argp)
783 {
784   PetscErrorCode ierr;
785 
786   PetscFunctionBegin;
787   if (fd != stdout && fd != stderr) { /* handle regular files */
788     ierr = PetscVFPrintfDefault(fd,format,Argp);CHKERRQ(ierr);
789   } else {
790     size_t length;
791     char   buff[length];
792 
793     ierr = PetscVSNPrintf(buff,sizeof(buff),format,&length,Argp);CHKERRQ(ierr);
794     mexPrintf("%s",buff);
795   }
796   PetscFunctionReturn(0);
797 }
798 #endif
799 
800 /*@C
801      PetscFormatStrip - Takes a PETSc format string and removes all numerical modifiers to % operations
802 
803    Input Parameters:
804 .   format - the PETSc format string
805 
806  Level: developer
807 
808 @*/
809 PetscErrorCode PetscFormatStrip(char *format)
810 {
811   size_t loc1 = 0, loc2 = 0;
812 
813   PetscFunctionBegin;
814   while (format[loc2]) {
815     if (format[loc2] == '%') {
816       format[loc1++] = format[loc2++];
817       while (format[loc2] && ((format[loc2] >= '0' && format[loc2] <= '9') || format[loc2] == '.')) loc2++;
818     }
819     format[loc1++] = format[loc2++];
820   }
821   PetscFunctionReturn(0);
822 }
823 
824 PetscErrorCode PetscFormatRealArray(char buf[],size_t len,const char *fmt,PetscInt n,const PetscReal x[])
825 {
826   PetscErrorCode ierr;
827   PetscInt       i;
828   size_t         left,count;
829   char           *p;
830 
831   PetscFunctionBegin;
832   for (i=0,p=buf,left=len; i<n; i++) {
833     ierr = PetscSNPrintfCount(p,left,fmt,&count,(double)x[i]);CHKERRQ(ierr);
834     if (count >= left) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Insufficient space in buffer");
835     left -= count;
836     p    += count-1;
837     *p++  = ' ';
838   }
839   p[i ? 0 : -1] = 0;
840   PetscFunctionReturn(0);
841 }
842