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