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