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