xref: /petsc/src/sys/fileio/mprint.c (revision e600fa544e2bb197ca2af9b6e65ea465976dec56)
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 PETSC_INTERN 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 = NULL;
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 = NULL;
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   size_t   sz = 0;
41   PetscInt i  = 0;
42 
43   PetscFunctionBegin;
44   PetscValidCharPointer(format,1);
45   PetscValidPointer(size,2);
46   while (format[i]) {
47     if (format[i] == '%') {
48       if (format[i+1] == '%') {
49         i  += 2;
50         sz += 2;
51         continue;
52       }
53       /* Find the letter */
54       while (format[i] && (format[i] <= '9')) {++i;++sz;}
55       switch (format[i]) {
56 #if PetscDefined(USE_64BIT_INDICES)
57       case 'D':
58         sz += 2;
59         break;
60 #endif
61       case 'g':
62         sz += 4;
63       default:
64         break;
65       }
66     }
67     ++i;
68     ++sz;
69   }
70   *size = sz+1; /* space for NULL character */
71   PetscFunctionReturn(0);
72 }
73 
74 /*@C
75      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
76                         converts %g to [|%g|] so that PetscVSNPrintf() can easily insure all %g formatted numbers have a decimal point when printed.
77 
78    Input Parameters:
79 +   format - the PETSc format string
80 .   newformat - the location to put the new format
81 -   size - the length of newformat, you can use PetscFormatConvertGetSize() to compute the needed size
82 
83     Note: this exists so we can have the same code when PetscInt is either int or long long int
84 
85  Level: developer
86 
87 .seealso: PetscFormatConvertGetSize(), PetscVSNPrintf(), PetscVFPrintf()
88 
89 @*/
90 PetscErrorCode PetscFormatConvert(const char *format,char *newformat)
91 {
92   PetscInt i = 0, j = 0;
93 
94   PetscFunctionBegin;
95   while (format[i]) {
96     if (format[i] == '%' && format[i+1] == '%') {
97       newformat[j++] = format[i++];
98       newformat[j++] = format[i++];
99     } else if (format[i] == '%') {
100       if (format[i+1] == 'g') {
101         newformat[j++] = '[';
102         newformat[j++] = '|';
103       }
104       /* Find the letter */
105       for (; format[i] && format[i] <= '9'; i++) newformat[j++] = format[i];
106       switch (format[i]) {
107       case 'D':
108 #if !defined(PETSC_USE_64BIT_INDICES)
109         newformat[j++] = 'd';
110 #else
111         newformat[j++] = 'l';
112         newformat[j++] = 'l';
113         newformat[j++] = 'd';
114 #endif
115         break;
116       case 'g':
117         newformat[j++] = format[i];
118         if (format[i-1] == '%') {
119           newformat[j++] = '|';
120           newformat[j++] = ']';
121         }
122         break;
123       case 'G':
124         SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"%%G format is no longer supported, use %%g and cast the argument to double");
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       default:
128         newformat[j++] = format[i];
129         break;
130       }
131       i++;
132     } else newformat[j++] = format[i++];
133   }
134   newformat[j] = 0;
135   PetscFunctionReturn(0);
136 }
137 
138 #define PETSCDEFAULTBUFFERSIZE 8*1024
139 
140 /*@C
141      PetscVSNPrintf - The PETSc version of vsnprintf(). Converts a PETSc format string into a standard C format string and then puts all the
142        function arguments into a string using the format statement.
143 
144    Input Parameters:
145 +   str - location to put result
146 .   len - the amount of space in str
147 +   format - the PETSc format string
148 -   fullLength - the amount of space in str actually used.
149 
150     Developer Notes:
151     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[PETSCDEFAULTBUFFERSIZE];
163   size_t         newLength;
164   PetscErrorCode ierr;
165   int            flen;
166 
167   PetscFunctionBegin;
168   ierr = PetscFormatConvertGetSize(format,&newLength);CHKERRQ(ierr);
169   if (newLength < PETSCDEFAULTBUFFERSIZE) {
170     newformat = formatbuf;
171     newLength = PETSCDEFAULTBUFFERSIZE-1;
172   } else {
173     ierr      = PetscMalloc1(newLength, &newformat);CHKERRQ(ierr);
174   }
175   ierr = PetscFormatConvert(format,newformat);CHKERRQ(ierr);
176 #if defined(PETSC_HAVE_VSNPRINTF)
177   flen = vsnprintf(str,len,newformat,Argp);
178 #else
179 #error "vsnprintf not found"
180 #endif
181   if (newLength > PETSCDEFAULTBUFFERSIZE-1) {
182     ierr = PetscFree(newformat);CHKERRQ(ierr);
183   }
184   {
185     PetscBool foundedot;
186     size_t cnt = 0,ncnt = 0,leng;
187     ierr = PetscStrlen(str,&leng);CHKERRQ(ierr);
188     if (leng > 4) {
189       for (cnt=0; cnt<leng-4; cnt++) {
190         if (str[cnt] == '[' && str[cnt+1] == '|') {
191           flen -= 4;
192           cnt++; cnt++;
193           foundedot = PETSC_FALSE;
194           for (; cnt<leng-1; cnt++) {
195             if (str[cnt] == '|' && str[cnt+1] == ']') {
196               cnt++;
197               if (!foundedot) str[ncnt++] = '.';
198               ncnt--;
199               break;
200             } else {
201               if (str[cnt] == 'e' || str[cnt] == '.') foundedot = PETSC_TRUE;
202               str[ncnt++] = str[cnt];
203             }
204           }
205         } else {
206           str[ncnt] = str[cnt];
207         }
208         ncnt++;
209       }
210       while (cnt < leng) {
211         str[ncnt] = str[cnt]; ncnt++; cnt++;
212       }
213       str[ncnt] = 0;
214     }
215   }
216 #if defined(PETSC_HAVE_WINDOWS_H) && !defined(PETSC_HAVE__SET_OUTPUT_FORMAT)
217   /* older Windows OS always produces e-+0np for floating point output; remove the extra 0 */
218   {
219     size_t cnt = 0,ncnt = 0,leng;
220     ierr = PetscStrlen(str,&leng);CHKERRQ(ierr);
221     if (leng > 5) {
222       for (cnt=0; cnt<leng-4; cnt++) {
223         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') {
224           str[ncnt] = str[cnt]; ncnt++; cnt++;
225           str[ncnt] = str[cnt]; ncnt++; cnt++; cnt++;
226           str[ncnt] = str[cnt];
227         } else {
228           str[ncnt] = str[cnt];
229         }
230         ncnt++;
231       }
232       while (cnt < leng) {
233         str[ncnt] = str[cnt]; ncnt++; cnt++;
234       }
235       str[ncnt] = 0;
236     }
237   }
238 #endif
239   if (fullLength) *fullLength = 1 + (size_t) flen;
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);
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 that are to be printed, each much have an appropriate symbol in the format argument
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 that are to be printed, each much have an appropriate symbol in the format argument
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       = NULL,petsc_printfqueuebase = NULL;
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   PetscCheckFalse(comm == MPI_COMM_NULL,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Called with MPI_COMM_NULL, likely PetscObjectComm() failed");
403   ierr = MPI_Comm_rank(comm,&rank);CHKERRMPI(ierr);
404 
405   /* First processor prints immediately to stdout */
406   if (rank == 0) {
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 = NULL;
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 = PetscArrayzero(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   PetscCheckFalse(comm == MPI_COMM_NULL,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Called with MPI_COMM_NULL, likely PetscObjectComm() failed");
471   ierr = MPI_Comm_rank(comm,&rank);CHKERRMPI(ierr);
472 
473   /* First processor prints immediately to fp */
474   if (rank == 0) {
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 = NULL;
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 = PetscArrayzero(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
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);CHKERRMPI(ierr);
541   ierr = MPI_Comm_size(comm,&size);CHKERRMPI(ierr);
542 
543   /* First processor waits for messages from all other processors */
544   if (rank == 0) {
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);CHKERRMPI(ierr);
549       ierr = MPI_Recv(&n,1,MPI_INT,i,tag,comm,&status);CHKERRMPI(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);CHKERRMPI(ierr);
554         ierr = PetscMalloc1(size, &message);CHKERRQ(ierr);
555         ierr = MPI_Recv(message,size,MPI_CHAR,i,tag,comm,&status);CHKERRMPI(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);CHKERRMPI(ierr);
564     ierr = MPI_Send(&petsc_printfqueuelength,1,MPI_INT,0,tag,comm);CHKERRMPI(ierr);
565     for (i=0; i<petsc_printfqueuelength; i++) {
566       ierr     = MPI_Send(&next->size,1,MPI_INT,0,tag,comm);CHKERRMPI(ierr);
567       ierr     = MPI_Send(next->string,next->size,MPI_CHAR,0,tag,comm);CHKERRMPI(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       = NULL;
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 .seealso: PetscPrintf(), PetscSynchronizedPrintf(), PetscViewerASCIIPrintf(),
599           PetscViewerASCIISynchronizedPrintf(), PetscSynchronizedFlush()
600 @*/
601 PetscErrorCode PetscFPrintf(MPI_Comm comm,FILE* fd,const char format[],...)
602 {
603   PetscErrorCode ierr;
604   PetscMPIInt    rank;
605 
606   PetscFunctionBegin;
607   PetscCheckFalse(comm == MPI_COMM_NULL,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Called with MPI_COMM_NULL, likely PetscObjectComm() failed");
608   ierr = MPI_Comm_rank(comm,&rank);CHKERRMPI(ierr);
609   if (rank == 0) {
610     va_list Argp;
611     va_start(Argp,format);
612     ierr = (*PetscVFPrintf)(fd,format,Argp);CHKERRQ(ierr);
613     if (petsc_history && (fd !=petsc_history)) {
614       va_start(Argp,format);
615       ierr = (*PetscVFPrintf)(petsc_history,format,Argp);CHKERRQ(ierr);
616     }
617     va_end(Argp);
618   }
619   PetscFunctionReturn(0);
620 }
621 
622 /*@C
623     PetscPrintf - Prints to standard out, only from the first
624     processor in the communicator. Calls from other processes are ignored.
625 
626     Not Collective
627 
628     Input Parameters:
629 +   comm - the communicator
630 -   format - the usual printf() format string
631 
632     Level: intermediate
633 
634     Notes:
635     PetscPrintf() supports some format specifiers that are unique to PETSc.
636     See the manual page for PetscFormatConvert() for details.
637 
638     Fortran Note:
639     The call sequence is PetscPrintf(MPI_Comm, character(*), PetscErrorCode ierr) from Fortran.
640     That is, you can only pass a single character string from Fortran.
641 
642 .seealso: PetscFPrintf(), PetscSynchronizedPrintf(), PetscFormatConvert()
643 @*/
644 PetscErrorCode PetscPrintf(MPI_Comm comm,const char format[],...)
645 {
646   PetscErrorCode ierr;
647   PetscMPIInt    rank;
648 
649   PetscFunctionBegin;
650   PetscCheckFalse(comm == MPI_COMM_NULL,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Called with MPI_COMM_NULL, likely PetscObjectComm() failed");
651   ierr = MPI_Comm_rank(comm,&rank);CHKERRMPI(ierr);
652   if (rank == 0) {
653     va_list Argp;
654     va_start(Argp,format);
655     ierr = (*PetscVFPrintf)(PETSC_STDOUT,format,Argp);CHKERRQ(ierr);
656     if (petsc_history) {
657       va_start(Argp,format);
658       ierr = (*PetscVFPrintf)(petsc_history,format,Argp);CHKERRQ(ierr);
659     }
660     va_end(Argp);
661   }
662   PetscFunctionReturn(0);
663 }
664 
665 PetscErrorCode PetscHelpPrintfDefault(MPI_Comm comm,const char format[],...)
666 {
667   PetscErrorCode ierr;
668   PetscMPIInt    rank;
669 
670   PetscFunctionBegin;
671   PetscCheckFalse(comm == MPI_COMM_NULL,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Called with MPI_COMM_NULL, likely PetscObjectComm() failed");
672   ierr = MPI_Comm_rank(comm,&rank);CHKERRMPI(ierr);
673   if (rank == 0) {
674     va_list Argp;
675     va_start(Argp,format);
676     ierr = (*PetscVFPrintf)(PETSC_STDOUT,format,Argp);CHKERRQ(ierr);
677     if (petsc_history) {
678       va_start(Argp,format);
679       ierr = (*PetscVFPrintf)(petsc_history,format,Argp);CHKERRQ(ierr);
680     }
681     va_end(Argp);
682   }
683   PetscFunctionReturn(0);
684 }
685 
686 /* ---------------------------------------------------------------------------------------*/
687 
688 /*@C
689     PetscSynchronizedFGets - Several processors all get the same line from a file.
690 
691     Collective
692 
693     Input Parameters:
694 +   comm - the communicator
695 .   fd - the file pointer
696 -   len - the length of the output buffer
697 
698     Output Parameter:
699 .   string - the line read from the file, at end of file string[0] == 0
700 
701     Level: intermediate
702 
703 .seealso: PetscSynchronizedPrintf(), PetscSynchronizedFlush(),
704           PetscFOpen(), PetscViewerASCIISynchronizedPrintf(), PetscViewerASCIIPrintf()
705 
706 @*/
707 PetscErrorCode PetscSynchronizedFGets(MPI_Comm comm,FILE *fp,size_t len,char string[])
708 {
709   PetscErrorCode ierr;
710   PetscMPIInt    rank;
711 
712   PetscFunctionBegin;
713   ierr = MPI_Comm_rank(comm,&rank);CHKERRMPI(ierr);
714 
715   if (rank == 0) {
716     char *ptr = fgets(string, len, fp);
717 
718     if (!ptr) {
719       string[0] = 0;
720       PetscCheckFalse(!feof(fp),PETSC_COMM_SELF, PETSC_ERR_FILE_READ, "Error reading from file: %d", errno);
721     }
722   }
723   ierr = MPI_Bcast(string,len,MPI_BYTE,0,comm);CHKERRMPI(ierr);
724   PetscFunctionReturn(0);
725 }
726 
727 #if defined(PETSC_HAVE_CLOSURE)
728 int (^SwiftClosure)(const char*) = 0;
729 
730 PetscErrorCode PetscVFPrintfToString(FILE *fd,const char format[],va_list Argp)
731 {
732   PetscErrorCode ierr;
733 
734   PetscFunctionBegin;
735   if (fd != stdout && fd != stderr) { /* handle regular files */
736     ierr = PetscVFPrintfDefault(fd,format,Argp);CHKERRQ(ierr);
737   } else {
738     size_t length;
739     char   buff[PETSCDEFAULTBUFFERSIZE];
740 
741     ierr = PetscVSNPrintf(buff,sizeof(buff),format,&length,Argp);CHKERRQ(ierr);
742     ierr = SwiftClosure(buff);CHKERRQ(ierr);
743   }
744   PetscFunctionReturn(0);
745 }
746 
747 /*
748    Provide a Swift function that processes all the PETSc calls to PetscVFPrintf()
749 */
750 PetscErrorCode PetscVFPrintfSetClosure(int (^closure)(const char*))
751 {
752   PetscVFPrintf = PetscVFPrintfToString;
753   SwiftClosure  = closure;
754   return 0;
755 }
756 #endif
757 
758 /*@C
759      PetscFormatStrip - Takes a PETSc format string and removes all numerical modifiers to % operations
760 
761    Input Parameters:
762 .   format - the PETSc format string
763 
764  Level: developer
765 
766 @*/
767 PetscErrorCode PetscFormatStrip(char *format)
768 {
769   size_t loc1 = 0, loc2 = 0;
770 
771   PetscFunctionBegin;
772   while (format[loc2]) {
773     if (format[loc2] == '%') {
774       format[loc1++] = format[loc2++];
775       while (format[loc2] && ((format[loc2] >= '0' && format[loc2] <= '9') || format[loc2] == '.')) loc2++;
776     }
777     format[loc1++] = format[loc2++];
778   }
779   PetscFunctionReturn(0);
780 }
781 
782 PetscErrorCode PetscFormatRealArray(char buf[],size_t len,const char *fmt,PetscInt n,const PetscReal x[])
783 {
784   PetscErrorCode ierr;
785   PetscInt       i;
786   size_t         left,count;
787   char           *p;
788 
789   PetscFunctionBegin;
790   for (i=0,p=buf,left=len; i<n; i++) {
791     ierr = PetscSNPrintfCount(p,left,fmt,&count,(double)x[i]);CHKERRQ(ierr);
792     PetscCheckFalse(count >= left,PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Insufficient space in buffer");
793     left -= count;
794     p    += count-1;
795     *p++  = ' ';
796   }
797   p[i ? 0 : -1] = 0;
798   PetscFunctionReturn(0);
799 }
800