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