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