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