xref: /petsc/src/sys/classes/viewer/impls/ascii/filev.c (revision 9d2ffcd05da5025bde689a57482bdbeea04a4861)
1 
2 #include <../src/sys/classes/viewer/impls/ascii/asciiimpl.h> /*I "petscviewer.h" I*/
3 
4 #define QUEUESTRINGSIZE 8192
5 
6 static PetscErrorCode PetscViewerFileClose_ASCII(PetscViewer viewer)
7 {
8   PetscMPIInt        rank;
9   PetscViewer_ASCII *vascii = (PetscViewer_ASCII *)viewer->data;
10   int                err;
11 
12   PetscFunctionBegin;
13   PetscCheck(!vascii->sviewer, PetscObjectComm((PetscObject)viewer), PETSC_ERR_ARG_WRONGSTATE, "Cannot call with outstanding call to PetscViewerRestoreSubViewer()");
14   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank));
15   if (rank == 0 && vascii->fd != stderr && vascii->fd != PETSC_STDOUT) {
16     if (vascii->fd && vascii->closefile) {
17       err = fclose(vascii->fd);
18       PetscCheck(!err, PETSC_COMM_SELF, PETSC_ERR_SYS, "fclose() failed on file");
19     }
20     if (vascii->storecompressed) {
21       char  par[PETSC_MAX_PATH_LEN], buf[PETSC_MAX_PATH_LEN];
22       FILE *fp;
23       PetscCall(PetscStrncpy(par, "gzip ", sizeof(par)));
24       PetscCall(PetscStrlcat(par, vascii->filename, sizeof(par)));
25 #if defined(PETSC_HAVE_POPEN)
26       PetscCall(PetscPOpen(PETSC_COMM_SELF, NULL, par, "r", &fp));
27       PetscCheck(!fgets(buf, 1024, fp), PETSC_COMM_SELF, PETSC_ERR_LIB, "Error from compression command %s\n%s", par, buf);
28       PetscCall(PetscPClose(PETSC_COMM_SELF, fp));
29 #else
30       SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP_SYS, "Cannot run external programs on this machine");
31 #endif
32     }
33   }
34   PetscCall(PetscFree(vascii->filename));
35   PetscFunctionReturn(PETSC_SUCCESS);
36 }
37 
38 /* ----------------------------------------------------------------------*/
39 PetscErrorCode PetscViewerDestroy_ASCII(PetscViewer viewer)
40 {
41   PetscViewer_ASCII *vascii = (PetscViewer_ASCII *)viewer->data;
42   PetscViewerLink   *vlink;
43   PetscBool          flg;
44 
45   PetscFunctionBegin;
46   PetscCheck(!vascii->sviewer, PetscObjectComm((PetscObject)viewer), PETSC_ERR_ARG_WRONGSTATE, "Cannot call with outstanding call to PetscViewerRestoreSubViewer()");
47   PetscCall(PetscViewerFileClose_ASCII(viewer));
48   PetscCall(PetscFree(vascii));
49 
50   /* remove the viewer from the list in the MPI Communicator */
51   if (Petsc_Viewer_keyval == MPI_KEYVAL_INVALID) PetscCallMPI(MPI_Comm_create_keyval(MPI_COMM_NULL_COPY_FN, Petsc_DelViewer, &Petsc_Viewer_keyval, (void *)0));
52 
53   PetscCallMPI(MPI_Comm_get_attr(PetscObjectComm((PetscObject)viewer), Petsc_Viewer_keyval, (void **)&vlink, (PetscMPIInt *)&flg));
54   if (flg) {
55     if (vlink && vlink->viewer == viewer) {
56       if (vlink->next) {
57         PetscCallMPI(MPI_Comm_set_attr(PetscObjectComm((PetscObject)viewer), Petsc_Viewer_keyval, vlink->next));
58       } else {
59         PetscCallMPI(MPI_Comm_delete_attr(PetscObjectComm((PetscObject)viewer), Petsc_Viewer_keyval));
60       }
61       PetscCall(PetscFree(vlink));
62     } else {
63       while (vlink && vlink->next) {
64         if (vlink->next->viewer == viewer) {
65           PetscViewerLink *nv = vlink->next;
66           vlink->next         = vlink->next->next;
67           PetscCall(PetscFree(nv));
68         }
69         vlink = vlink->next;
70       }
71     }
72   }
73 
74   if (Petsc_Viewer_Stdout_keyval != MPI_KEYVAL_INVALID) {
75     PetscViewer aviewer;
76     PetscCallMPI(MPI_Comm_get_attr(PetscObjectComm((PetscObject)viewer), Petsc_Viewer_Stdout_keyval, (void **)&aviewer, (PetscMPIInt *)&flg));
77     if (flg && aviewer == viewer) PetscCallMPI(MPI_Comm_delete_attr(PetscObjectComm((PetscObject)viewer), Petsc_Viewer_Stdout_keyval));
78   }
79   if (Petsc_Viewer_Stderr_keyval != MPI_KEYVAL_INVALID) {
80     PetscViewer aviewer;
81     PetscCallMPI(MPI_Comm_get_attr(PetscObjectComm((PetscObject)viewer), Petsc_Viewer_Stderr_keyval, (void **)&aviewer, (PetscMPIInt *)&flg));
82     if (flg && aviewer == viewer) PetscCallMPI(MPI_Comm_delete_attr(PetscObjectComm((PetscObject)viewer), Petsc_Viewer_Stderr_keyval));
83   }
84   PetscCall(PetscObjectComposeFunction((PetscObject)viewer, "PetscViewerFileSetName_C", NULL));
85   PetscCall(PetscObjectComposeFunction((PetscObject)viewer, "PetscViewerFileGetName_C", NULL));
86   PetscCall(PetscObjectComposeFunction((PetscObject)viewer, "PetscViewerFileGetMode_C", NULL));
87   PetscCall(PetscObjectComposeFunction((PetscObject)viewer, "PetscViewerFileSetMode_C", NULL));
88   PetscFunctionReturn(PETSC_SUCCESS);
89 }
90 
91 PetscErrorCode PetscViewerDestroy_ASCII_SubViewer(PetscViewer viewer)
92 {
93   PetscViewer_ASCII *vascii = (PetscViewer_ASCII *)viewer->data;
94 
95   PetscFunctionBegin;
96   PetscCall(PetscViewerRestoreSubViewer(vascii->bviewer, 0, &viewer));
97   PetscFunctionReturn(PETSC_SUCCESS);
98 }
99 
100 PetscErrorCode PetscViewerFlush_ASCII(PetscViewer viewer)
101 {
102   PetscViewer_ASCII *vascii = (PetscViewer_ASCII *)viewer->data;
103   MPI_Comm           comm;
104   PetscMPIInt        rank, size;
105   FILE              *fd = vascii->fd;
106 
107   PetscFunctionBegin;
108   PetscCheck(!vascii->sviewer, PetscObjectComm((PetscObject)viewer), PETSC_ERR_ARG_WRONGSTATE, "Cannot call with outstanding call to PetscViewerRestoreSubViewer()");
109   PetscCall(PetscObjectGetComm((PetscObject)viewer, &comm));
110   PetscCallMPI(MPI_Comm_rank(comm, &rank));
111   PetscCallMPI(MPI_Comm_size(comm, &size));
112 
113   if (!vascii->bviewer && rank == 0 && (vascii->mode != FILE_MODE_READ)) PetscCall(PetscFFlush(vascii->fd));
114 
115   if (vascii->allowsynchronized) {
116     PetscMPIInt tag, i, j, n = 0, dummy = 0;
117     char       *message;
118     MPI_Status  status;
119 
120     PetscCall(PetscCommDuplicate(comm, &comm, &tag));
121 
122     /* First processor waits for messages from all other processors */
123     if (rank == 0) {
124       /* flush my own messages that I may have queued up */
125       PrintfQueue next = vascii->petsc_printfqueuebase, previous;
126       for (i = 0; i < vascii->petsc_printfqueuelength; i++) {
127         if (!vascii->bviewer) {
128           PetscCall(PetscFPrintf(comm, fd, "%s", next->string));
129         } else {
130           PetscCall(PetscViewerASCIISynchronizedPrintf(vascii->bviewer, "%s", next->string));
131         }
132         previous = next;
133         next     = next->next;
134         PetscCall(PetscFree(previous->string));
135         PetscCall(PetscFree(previous));
136       }
137       vascii->petsc_printfqueue       = NULL;
138       vascii->petsc_printfqueuelength = 0;
139       for (i = 1; i < size; i++) {
140         /* to prevent a flood of messages to process zero, request each message separately */
141         PetscCallMPI(MPI_Send(&dummy, 1, MPI_INT, i, tag, comm));
142         PetscCallMPI(MPI_Recv(&n, 1, MPI_INT, i, tag, comm, &status));
143         for (j = 0; j < n; j++) {
144           PetscMPIInt size = 0;
145 
146           PetscCallMPI(MPI_Recv(&size, 1, MPI_INT, i, tag, comm, &status));
147           PetscCall(PetscMalloc1(size, &message));
148           PetscCallMPI(MPI_Recv(message, size, MPI_CHAR, i, tag, comm, &status));
149           if (!vascii->bviewer) {
150             PetscCall(PetscFPrintf(comm, fd, "%s", message));
151           } else {
152             PetscCall(PetscViewerASCIISynchronizedPrintf(vascii->bviewer, "%s", message));
153           }
154           PetscCall(PetscFree(message));
155         }
156       }
157     } else { /* other processors send queue to processor 0 */
158       PrintfQueue next = vascii->petsc_printfqueuebase, previous;
159 
160       PetscCallMPI(MPI_Recv(&dummy, 1, MPI_INT, 0, tag, comm, &status));
161       PetscCallMPI(MPI_Send(&vascii->petsc_printfqueuelength, 1, MPI_INT, 0, tag, comm));
162       for (i = 0; i < vascii->petsc_printfqueuelength; i++) {
163         PetscCallMPI(MPI_Send(&next->size, 1, MPI_INT, 0, tag, comm));
164         PetscCallMPI(MPI_Send(next->string, next->size, MPI_CHAR, 0, tag, comm));
165         previous = next;
166         next     = next->next;
167         PetscCall(PetscFree(previous->string));
168         PetscCall(PetscFree(previous));
169       }
170       vascii->petsc_printfqueue       = NULL;
171       vascii->petsc_printfqueuelength = 0;
172     }
173     PetscCall(PetscCommDestroy(&comm));
174   }
175   PetscFunctionReturn(PETSC_SUCCESS);
176 }
177 
178 /*@C
179     PetscViewerASCIIGetPointer - Extracts the file pointer from an ASCII `PetscViewer`.
180 
181     Not Collective, depending on the viewer the value may be meaningless except for process 0 of the viewer; No Fortran Support
182 
183     Input Parameter:
184 .    viewer - `PetscViewer` context, obtained from `PetscViewerASCIIOpen()`
185 
186     Output Parameter:
187 .    fd - file pointer
188 
189     Level: intermediate
190 
191     Note:
192     For the standard `PETSCVIEWERASCII` the value is valid only on MPI rank 0 of the viewer
193 
194 .seealso: [](sec_viewers), `PETSCVIEWERASCII`, `PetscViewerASCIIOpen()`, `PetscViewerDestroy()`, `PetscViewerSetType()`,
195           `PetscViewerCreate()`, `PetscViewerASCIIPrintf()`, `PetscViewerASCIISynchronizedPrintf()`, `PetscViewerFlush()`
196 @*/
197 PetscErrorCode PetscViewerASCIIGetPointer(PetscViewer viewer, FILE **fd)
198 {
199   PetscViewer_ASCII *vascii = (PetscViewer_ASCII *)viewer->data;
200 
201   PetscFunctionBegin;
202   *fd = vascii->fd;
203   PetscFunctionReturn(PETSC_SUCCESS);
204 }
205 
206 PetscErrorCode PetscViewerFileGetMode_ASCII(PetscViewer viewer, PetscFileMode *mode)
207 {
208   PetscViewer_ASCII *vascii = (PetscViewer_ASCII *)viewer->data;
209 
210   PetscFunctionBegin;
211   *mode = vascii->mode;
212   PetscFunctionReturn(PETSC_SUCCESS);
213 }
214 
215 PetscErrorCode PetscViewerFileSetMode_ASCII(PetscViewer viewer, PetscFileMode mode)
216 {
217   PetscViewer_ASCII *vascii = (PetscViewer_ASCII *)viewer->data;
218 
219   PetscFunctionBegin;
220   vascii->mode = mode;
221   PetscFunctionReturn(PETSC_SUCCESS);
222 }
223 
224 /*
225    If petsc_history is on, then all Petsc*Printf() results are saved
226    if the appropriate (usually .petschistory) file.
227 */
228 PETSC_INTERN FILE *petsc_history;
229 
230 /*@
231     PetscViewerASCIISetTab - Causes `PetscViewer` to tab in a number of times before printing
232 
233     Not Collective, but only first processor in set has any effect; No Fortran Support
234 
235     Input Parameters:
236 +    viewer - obtained with `PetscViewerASCIIOpen()`
237 -    tabs - number of tabs
238 
239     Level: developer
240 
241     Note:
242      `PetscViewerASCIIPushTab()` and `PetscViewerASCIIPopTab()` are the preferred usage
243 
244 .seealso: [](sec_viewers), `PETSCVIEWERASCII`, `PetscPrintf()`, `PetscSynchronizedPrintf()`, `PetscViewerASCIIPrintf()`,
245           `PetscViewerASCIIGetTab()`,
246           `PetscViewerASCIIPopTab()`, `PetscViewerASCIISynchronizedPrintf()`, `PetscViewerASCIIOpen()`,
247           `PetscViewerCreate()`, `PetscViewerDestroy()`, `PetscViewerSetType()`, `PetscViewerASCIIGetPointer()`,
248           `PetscViewerASCIIPushTab()`
249 @*/
250 PetscErrorCode PetscViewerASCIISetTab(PetscViewer viewer, PetscInt tabs)
251 {
252   PetscViewer_ASCII *ascii = (PetscViewer_ASCII *)viewer->data;
253   PetscBool          iascii;
254 
255   PetscFunctionBegin;
256   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
257   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
258   if (iascii) ascii->tab = tabs;
259   PetscFunctionReturn(PETSC_SUCCESS);
260 }
261 
262 /*@
263     PetscViewerASCIIGetTab - Return the number of tabs used by `PetscViewer`.
264 
265     Not Collective, meaningful on first processor only; No Fortran Support
266 
267     Input Parameter:
268 .    viewer - obtained with `PetscViewerASCIIOpen()`
269 
270     Output Parameter:
271 .    tabs - number of tabs
272 
273     Level: developer
274 
275 .seealso: [](sec_viewers), `PETSCVIEWERASCII`, `PetscPrintf()`, `PetscSynchronizedPrintf()`, `PetscViewerASCIIPrintf()`,
276           `PetscViewerASCIISetTab()`,
277           `PetscViewerASCIIPopTab()`, `PetscViewerASCIISynchronizedPrintf()`, `PetscViewerASCIIOpen()`,
278           `PetscViewerCreate()`, `PetscViewerDestroy()`, `PetscViewerSetType()`, `PetscViewerASCIIGetPointer()`, `PetscViewerASCIIPushTab()`
279 @*/
280 PetscErrorCode PetscViewerASCIIGetTab(PetscViewer viewer, PetscInt *tabs)
281 {
282   PetscViewer_ASCII *ascii = (PetscViewer_ASCII *)viewer->data;
283   PetscBool          iascii;
284 
285   PetscFunctionBegin;
286   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
287   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
288   if (iascii && tabs) *tabs = ascii->tab;
289   PetscFunctionReturn(PETSC_SUCCESS);
290 }
291 
292 /*@
293     PetscViewerASCIIAddTab - Add to the number of times a `PETSCVIEWERASCII` viewer tabs before printing
294 
295     Not Collective, but only first processor in set has any effect; No Fortran Support
296 
297     Input Parameters:
298 +    viewer - obtained with `PetscViewerASCIIOpen()`
299 -    tabs - number of tabs
300 
301     Level: developer
302 
303     Note:
304      `PetscViewerASCIIPushTab()` and `PetscViewerASCIIPopTab()` are the preferred usage
305 
306 .seealso: [](sec_viewers), `PETSCVIEWERASCII`, `PetscPrintf()`, `PetscSynchronizedPrintf()`, `PetscViewerASCIIPrintf()`,
307           `PetscViewerASCIIPopTab()`, `PetscViewerASCIISynchronizedPrintf()`, `PetscViewerASCIIOpen()`,
308           `PetscViewerCreate()`, `PetscViewerDestroy()`, `PetscViewerSetType()`, `PetscViewerASCIIGetPointer()`, `PetscViewerASCIIPushTab()`
309 @*/
310 PetscErrorCode PetscViewerASCIIAddTab(PetscViewer viewer, PetscInt tabs)
311 {
312   PetscViewer_ASCII *ascii = (PetscViewer_ASCII *)viewer->data;
313   PetscBool          iascii;
314 
315   PetscFunctionBegin;
316   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
317   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
318   if (iascii) ascii->tab += tabs;
319   PetscFunctionReturn(PETSC_SUCCESS);
320 }
321 
322 /*@
323     PetscViewerASCIISubtractTab - Subtracts from the number of times a `PETSCVIEWERASCII` viewer tabs before printing
324 
325     Not Collective, but only first processor in set has any effect; No Fortran Support
326 
327     Input Parameters:
328 +    viewer - obtained with `PetscViewerASCIIOpen()`
329 -    tabs - number of tabs
330 
331     Level: developer
332 
333     Note:
334      `PetscViewerASCIIPushTab()` and `PetscViewerASCIIPopTab()` are the preferred usage
335 
336 .seealso: [](sec_viewers), `PETSCVIEWERASCII`, `PetscPrintf()`, `PetscSynchronizedPrintf()`, `PetscViewerASCIIPrintf()`,
337           `PetscViewerASCIIPopTab()`, `PetscViewerASCIISynchronizedPrintf()`, `PetscViewerASCIIOpen()`,
338           `PetscViewerCreate()`, `PetscViewerDestroy()`, `PetscViewerSetType()`, `PetscViewerASCIIGetPointer()`,
339           `PetscViewerASCIIPushTab()`
340 @*/
341 PetscErrorCode PetscViewerASCIISubtractTab(PetscViewer viewer, PetscInt tabs)
342 {
343   PetscViewer_ASCII *ascii = (PetscViewer_ASCII *)viewer->data;
344   PetscBool          iascii;
345 
346   PetscFunctionBegin;
347   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
348   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
349   if (iascii) ascii->tab -= tabs;
350   PetscFunctionReturn(PETSC_SUCCESS);
351 }
352 
353 /*@C
354     PetscViewerASCIIPushSynchronized - Allows calls to `PetscViewerASCIISynchronizedPrintf()` for this viewer
355 
356     Collective
357 
358     Input Parameter:
359 .    viewer - obtained with `PetscViewerASCIIOpen()`
360 
361     Level: intermediate
362 
363     Note:
364     See documentation of `PetscViewerASCIISynchronizedPrintf()` for more details how the synchronized output should be done properly.
365 
366 .seealso: [](sec_viewers), `PetscViewerASCIISynchronizedPrintf()`, `PetscViewerFlush()`, `PetscViewerASCIIPopSynchronized()`,
367           `PetscSynchronizedPrintf()`, `PetscViewerASCIIPrintf()`, `PetscViewerASCIIOpen()`,
368           `PetscViewerCreate()`, `PetscViewerDestroy()`, `PetscViewerSetType()`
369 @*/
370 PetscErrorCode PetscViewerASCIIPushSynchronized(PetscViewer viewer)
371 {
372   PetscViewer_ASCII *ascii = (PetscViewer_ASCII *)viewer->data;
373   PetscBool          iascii;
374 
375   PetscFunctionBegin;
376   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
377   PetscCheck(!ascii->sviewer, PetscObjectComm((PetscObject)viewer), PETSC_ERR_ARG_WRONGSTATE, "Cannot call with outstanding call to PetscViewerRestoreSubViewer()");
378   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
379   if (iascii) ascii->allowsynchronized++;
380   PetscFunctionReturn(PETSC_SUCCESS);
381 }
382 
383 /*@C
384     PetscViewerASCIIPopSynchronized - Undoes most recent `PetscViewerASCIIPushSynchronized()` for this viewer
385 
386     Collective
387 
388     Input Parameter:
389 .    viewer - obtained with `PetscViewerASCIIOpen()`
390 
391     Level: intermediate
392 
393     Note:
394     See documentation of `PetscViewerASCIISynchronizedPrintf()` for more details how the synchronized output should be done properly.
395 
396 .seealso: [](sec_viewers), `PetscViewerASCIIPushSynchronized()`, `PetscViewerASCIISynchronizedPrintf()`, `PetscViewerFlush()`,
397           `PetscSynchronizedPrintf()`, `PetscViewerASCIIPrintf()`, `PetscViewerASCIIOpen()`,
398           `PetscViewerCreate()`, `PetscViewerDestroy()`, `PetscViewerSetType()`
399 @*/
400 PetscErrorCode PetscViewerASCIIPopSynchronized(PetscViewer viewer)
401 {
402   PetscViewer_ASCII *ascii = (PetscViewer_ASCII *)viewer->data;
403   PetscBool          iascii;
404 
405   PetscFunctionBegin;
406   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
407   PetscCheck(!ascii->sviewer, PetscObjectComm((PetscObject)viewer), PETSC_ERR_ARG_WRONGSTATE, "Cannot call with outstanding call to PetscViewerRestoreSubViewer()");
408   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
409   if (iascii) {
410     ascii->allowsynchronized--;
411     PetscCheck(ascii->allowsynchronized >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Called more times than PetscViewerASCIIPushSynchronized()");
412   }
413   PetscFunctionReturn(PETSC_SUCCESS);
414 }
415 
416 /*@C
417     PetscViewerASCIIPushTab - Adds one more tab to the amount that `PetscViewerASCIIPrintf()`
418      lines are tabbed.
419 
420     Not Collective, but only first MPI rank in the viewer has any effect; No Fortran Support
421 
422     Input Parameter:
423 .    viewer - obtained with `PetscViewerASCIIOpen()`
424 
425     Level: developer
426 
427 .seealso: [](sec_viewers), `PetscPrintf()`, `PetscSynchronizedPrintf()`, `PetscViewerASCIIPrintf()`,
428           `PetscViewerASCIIPopTab()`, `PetscViewerASCIISynchronizedPrintf()`, `PetscViewerASCIIOpen()`,
429           `PetscViewerCreate()`, `PetscViewerDestroy()`, `PetscViewerSetType()`, `PetscViewerASCIIGetPointer()`
430 @*/
431 PetscErrorCode PetscViewerASCIIPushTab(PetscViewer viewer)
432 {
433   PetscViewer_ASCII *ascii = (PetscViewer_ASCII *)viewer->data;
434   PetscBool          iascii;
435 
436   PetscFunctionBegin;
437   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
438   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
439   if (iascii) ascii->tab++;
440   PetscFunctionReturn(PETSC_SUCCESS);
441 }
442 
443 /*@C
444     PetscViewerASCIIPopTab - Removes one tab from the amount that `PetscViewerASCIIPrintf()` lines are tabbed that was provided by
445     `PetscViewerASCIIPushTab()`
446 
447     Not Collective, but only first MPI rank in the viewer has any effect; No Fortran Support
448 
449     Input Parameter:
450 .    viewer - obtained with `PetscViewerASCIIOpen()`
451 
452     Level: developer
453 
454 .seealso: [](sec_viewers), `PetscPrintf()`, `PetscSynchronizedPrintf()`, `PetscViewerASCIIPrintf()`,
455           `PetscViewerASCIIPushTab()`, `PetscViewerASCIISynchronizedPrintf()`, `PetscViewerASCIIOpen()`,
456           `PetscViewerCreate()`, `PetscViewerDestroy()`, `PetscViewerSetType()`, `PetscViewerASCIIGetPointer()`
457 @*/
458 PetscErrorCode PetscViewerASCIIPopTab(PetscViewer viewer)
459 {
460   PetscViewer_ASCII *ascii = (PetscViewer_ASCII *)viewer->data;
461   PetscBool          iascii;
462 
463   PetscFunctionBegin;
464   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
465   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
466   if (iascii) {
467     PetscCheck(ascii->tab > 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "More tabs popped than pushed");
468     ascii->tab--;
469   }
470   PetscFunctionReturn(PETSC_SUCCESS);
471 }
472 
473 /*@
474     PetscViewerASCIIUseTabs - Turns on or off the use of tabs with the `PETSCVIEWERASCII` `PetscViewer`
475 
476     Not Collective, but only first MPI rank in the viewer has any effect; No Fortran Support
477 
478     Input Parameters:
479 +    viewer - obtained with `PetscViewerASCIIOpen()`
480 -    flg - `PETSC_TRUE` or `PETSC_FALSE`
481 
482     Level: developer
483 
484 .seealso: [](sec_viewers), `PetscPrintf()`, `PetscSynchronizedPrintf()`, `PetscViewerASCIIPrintf()`,
485           `PetscViewerASCIIPopTab()`, `PetscViewerASCIISynchronizedPrintf()`, `PetscViewerASCIIPushTab()`, `PetscViewerASCIIOpen()`,
486           `PetscViewerCreate()`, `PetscViewerDestroy()`, `PetscViewerSetType()`, `PetscViewerASCIIGetPointer()`
487 @*/
488 PetscErrorCode PetscViewerASCIIUseTabs(PetscViewer viewer, PetscBool flg)
489 {
490   PetscViewer_ASCII *ascii = (PetscViewer_ASCII *)viewer->data;
491   PetscBool          iascii;
492 
493   PetscFunctionBegin;
494   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
495   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
496   if (iascii) {
497     if (flg) ascii->tab = ascii->tab_store;
498     else {
499       ascii->tab_store = ascii->tab;
500       ascii->tab       = 0;
501     }
502   }
503   PetscFunctionReturn(PETSC_SUCCESS);
504 }
505 
506 /*@C
507     PetscViewerASCIIPrintf - Prints to a file, only from the first
508     processor in the `PetscViewer` of type `PETSCVIEWERASCII`
509 
510     Not Collective, but only the first MPI rank in the viewer has any effect
511 
512     Input Parameters:
513 +    viewer - obtained with `PetscViewerASCIIOpen()`
514 -    format - the usual printf() format string
515 
516     Level: developer
517 
518     Fortran Note:
519     The call sequence is `PetscViewerASCIIPrintf`(`PetscViewer`, character(*), int ierr) from Fortran.
520     That is, you can only pass a single character string from Fortran.
521 
522 .seealso: [](sec_viewers), `PetscPrintf()`, `PetscSynchronizedPrintf()`, `PetscViewerASCIIOpen()`,
523           `PetscViewerASCIIPushTab()`, `PetscViewerASCIIPopTab()`, `PetscViewerASCIISynchronizedPrintf()`,
524           `PetscViewerCreate()`, `PetscViewerDestroy()`, `PetscViewerSetType()`, `PetscViewerASCIIGetPointer()`, `PetscViewerASCIIPushSynchronized()`
525 @*/
526 PetscErrorCode PetscViewerASCIIPrintf(PetscViewer viewer, const char format[], ...)
527 {
528   PetscViewer_ASCII *ascii = (PetscViewer_ASCII *)viewer->data;
529   PetscMPIInt        rank;
530   PetscInt           tab, intab = ascii->tab;
531   FILE              *fd = ascii->fd;
532   PetscBool          iascii;
533 
534   PetscFunctionBegin;
535   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
536   PetscCheck(!ascii->sviewer, PetscObjectComm((PetscObject)viewer), PETSC_ERR_ARG_WRONGSTATE, "Cannot call with outstanding call to PetscViewerRestoreSubViewer()");
537   PetscValidCharPointer(format, 2);
538   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
539   PetscCheck(iascii, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Not ASCII PetscViewer");
540   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank));
541   if (rank) PetscFunctionReturn(PETSC_SUCCESS);
542 
543   if (ascii->bviewer) { /* pass string up to parent viewer */
544     char   *string;
545     va_list Argp;
546     size_t  fullLength;
547 
548     PetscCall(PetscCalloc1(QUEUESTRINGSIZE, &string));
549     va_start(Argp, format);
550     PetscCall(PetscVSNPrintf(string, QUEUESTRINGSIZE, format, &fullLength, Argp));
551     va_end(Argp);
552     PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%s", string));
553     PetscCall(PetscFree(string));
554   } else { /* write directly to file */
555     va_list Argp;
556     /* flush my own messages that I may have queued up */
557     PrintfQueue next = ascii->petsc_printfqueuebase, previous;
558     PetscInt    i;
559     for (i = 0; i < ascii->petsc_printfqueuelength; i++) {
560       PetscCall(PetscFPrintf(PETSC_COMM_SELF, fd, "%s", next->string));
561       previous = next;
562       next     = next->next;
563       PetscCall(PetscFree(previous->string));
564       PetscCall(PetscFree(previous));
565     }
566     ascii->petsc_printfqueue       = NULL;
567     ascii->petsc_printfqueuelength = 0;
568     tab                            = intab;
569     while (tab--) PetscCall(PetscFPrintf(PETSC_COMM_SELF, fd, "  "));
570 
571     va_start(Argp, format);
572     PetscCall((*PetscVFPrintf)(fd, format, Argp));
573     va_end(Argp);
574     PetscCall(PetscFFlush(fd));
575     if (petsc_history) {
576       tab = intab;
577       while (tab--) PetscCall(PetscFPrintf(PETSC_COMM_SELF, petsc_history, "  "));
578       va_start(Argp, format);
579       PetscCall((*PetscVFPrintf)(petsc_history, format, Argp));
580       va_end(Argp);
581       PetscCall(PetscFFlush(petsc_history));
582     }
583   }
584   PetscFunctionReturn(PETSC_SUCCESS);
585 }
586 
587 /*@C
588      PetscViewerFileSetName - Sets the name of the file the `PetscViewer` should use.
589 
590     Collective
591 
592   Input Parameters:
593 +  viewer - the `PetscViewer`; for example, of type `PETSCVIEWERASCII` or `PETSCVIEWERBINARY`
594 -  name - the name of the file it should use
595 
596     Level: advanced
597 
598   Note:
599   This will have no effect on viewers that are not related to files
600 
601 .seealso: [](sec_viewers), `PetscViewerCreate()`, `PetscViewerSetType()`, `PetscViewerASCIIOpen()`, `PetscViewerBinaryOpen()`, `PetscViewerDestroy()`,
602           `PetscViewerASCIIGetPointer()`, `PetscViewerASCIIPrintf()`, `PetscViewerASCIISynchronizedPrintf()`
603 @*/
604 PetscErrorCode PetscViewerFileSetName(PetscViewer viewer, const char name[])
605 {
606   char filename[PETSC_MAX_PATH_LEN];
607 
608   PetscFunctionBegin;
609   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
610   PetscValidCharPointer(name, 2);
611   PetscCall(PetscStrreplace(PetscObjectComm((PetscObject)viewer), name, filename, sizeof(filename)));
612   PetscTryMethod(viewer, "PetscViewerFileSetName_C", (PetscViewer, const char[]), (viewer, filename));
613   PetscFunctionReturn(PETSC_SUCCESS);
614 }
615 
616 /*@C
617      PetscViewerFileGetName - Gets the name of the file the `PetscViewer` is using
618 
619     Not Collective
620 
621   Input Parameter:
622 .  viewer - the `PetscViewer`
623 
624   Output Parameter:
625 .  name - the name of the file it is using
626 
627     Level: advanced
628 
629   Note:
630   This will have no effect on viewers that are not related to files
631 
632 .seealso: [](sec_viewers), `PetscViewerCreate()`, `PetscViewerSetType()`, `PetscViewerASCIIOpen()`, `PetscViewerBinaryOpen()`, `PetscViewerFileSetName()`
633 @*/
634 PetscErrorCode PetscViewerFileGetName(PetscViewer viewer, const char **name)
635 {
636   PetscFunctionBegin;
637   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
638   PetscValidPointer(name, 2);
639   PetscUseMethod(viewer, "PetscViewerFileGetName_C", (PetscViewer, const char **), (viewer, name));
640   PetscFunctionReturn(PETSC_SUCCESS);
641 }
642 
643 PetscErrorCode PetscViewerFileGetName_ASCII(PetscViewer viewer, const char **name)
644 {
645   PetscViewer_ASCII *vascii = (PetscViewer_ASCII *)viewer->data;
646 
647   PetscFunctionBegin;
648   *name = vascii->filename;
649   PetscFunctionReturn(PETSC_SUCCESS);
650 }
651 
652 PetscErrorCode PetscViewerFileSetName_ASCII(PetscViewer viewer, const char name[])
653 {
654   size_t             len;
655   char               fname[PETSC_MAX_PATH_LEN], *gz = NULL;
656   PetscViewer_ASCII *vascii = (PetscViewer_ASCII *)viewer->data;
657   PetscBool          isstderr, isstdout;
658   PetscMPIInt        rank;
659 
660   PetscFunctionBegin;
661   PetscCall(PetscViewerFileClose_ASCII(viewer));
662   if (!name) PetscFunctionReturn(PETSC_SUCCESS);
663   PetscCall(PetscStrallocpy(name, &vascii->filename));
664 
665   /* Is this file to be compressed */
666   vascii->storecompressed = PETSC_FALSE;
667 
668   PetscCall(PetscStrstr(vascii->filename, ".gz", &gz));
669   if (gz) {
670     PetscCall(PetscStrlen(gz, &len));
671     if (len == 3) {
672       PetscCheck(vascii->mode == FILE_MODE_WRITE, PetscObjectComm((PetscObject)viewer), PETSC_ERR_SUP, "Cannot open ASCII PetscViewer file that is compressed; uncompress it manually first");
673       *gz                     = 0;
674       vascii->storecompressed = PETSC_TRUE;
675     }
676   }
677   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank));
678   if (rank == 0) {
679     PetscCall(PetscStrcmp(name, "stderr", &isstderr));
680     PetscCall(PetscStrcmp(name, "stdout", &isstdout));
681     /* empty filename means stdout */
682     if (name[0] == 0) isstdout = PETSC_TRUE;
683     if (isstderr) vascii->fd = PETSC_STDERR;
684     else if (isstdout) vascii->fd = PETSC_STDOUT;
685     else {
686       PetscCall(PetscFixFilename(name, fname));
687       switch (vascii->mode) {
688       case FILE_MODE_READ:
689         vascii->fd = fopen(fname, "r");
690         break;
691       case FILE_MODE_WRITE:
692         vascii->fd = fopen(fname, "w");
693         break;
694       case FILE_MODE_APPEND:
695         vascii->fd = fopen(fname, "a");
696         break;
697       case FILE_MODE_UPDATE:
698         vascii->fd = fopen(fname, "r+");
699         if (!vascii->fd) vascii->fd = fopen(fname, "w+");
700         break;
701       case FILE_MODE_APPEND_UPDATE:
702         /* I really want a file which is opened at the end for updating,
703            not a+, which opens at the beginning, but makes writes at the end.
704         */
705         vascii->fd = fopen(fname, "r+");
706         if (!vascii->fd) vascii->fd = fopen(fname, "w+");
707         else {
708           int ret = fseek(vascii->fd, 0, SEEK_END);
709           PetscCheck(!ret, PETSC_COMM_SELF, PETSC_ERR_LIB, "fseek() failed with error code %d", ret);
710         }
711         break;
712       default:
713         SETERRQ(PetscObjectComm((PetscObject)viewer), PETSC_ERR_SUP, "Unsupported file mode %s", PetscFileModes[vascii->mode]);
714       }
715       PetscCheck(vascii->fd, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Cannot open PetscViewer file: %s", fname);
716     }
717   }
718 #if defined(PETSC_USE_LOG)
719   PetscCall(PetscLogObjectState((PetscObject)viewer, "File: %s", name));
720 #endif
721   PetscFunctionReturn(PETSC_SUCCESS);
722 }
723 
724 PetscErrorCode PetscViewerGetSubViewer_ASCII(PetscViewer viewer, MPI_Comm subcomm, PetscViewer *outviewer)
725 {
726   PetscViewer_ASCII *vascii = (PetscViewer_ASCII *)viewer->data, *ovascii;
727 
728   PetscFunctionBegin;
729   PetscCall(PetscViewerASCIIPushSynchronized(viewer));
730   PetscCheck(!vascii->sviewer, PETSC_COMM_SELF, PETSC_ERR_ORDER, "SubViewer already obtained from PetscViewer and not restored");
731   /*
732      The following line is a bug; it does another PetscViewerASCIIPushSynchronized() on viewer, but if it is removed the code won't work
733      because it relies on this behavior in other places. In particular this line causes the synchronized flush to occur when the viewer is destroyed
734      (since the count never gets to zero) in some examples this displays information that otherwise would be lost
735 
736      This code also means another call to PetscViewerASCIIPopSynchronized() must be made after the PetscViewerRestoreSubViewer(), see, for example,
737      PCView_GASM().
738   */
739   PetscCall(PetscViewerASCIIPushSynchronized(viewer));
740   PetscCall(PetscViewerCreate(subcomm, outviewer));
741   PetscCall(PetscViewerSetType(*outviewer, PETSCVIEWERASCII));
742   PetscCall(PetscViewerASCIIPushSynchronized(*outviewer));
743   ovascii            = (PetscViewer_ASCII *)(*outviewer)->data;
744   ovascii->fd        = vascii->fd;
745   ovascii->tab       = vascii->tab;
746   ovascii->closefile = PETSC_FALSE;
747 
748   vascii->sviewer                                      = *outviewer;
749   (*outviewer)->format                                 = viewer->format;
750   ((PetscViewer_ASCII *)((*outviewer)->data))->bviewer = viewer;
751   (*outviewer)->ops->destroy                           = PetscViewerDestroy_ASCII_SubViewer;
752   PetscFunctionReturn(PETSC_SUCCESS);
753 }
754 
755 PetscErrorCode PetscViewerRestoreSubViewer_ASCII(PetscViewer viewer, MPI_Comm comm, PetscViewer *outviewer)
756 {
757   PetscViewer_ASCII *ascii = (PetscViewer_ASCII *)viewer->data;
758 
759   PetscFunctionBegin;
760   PetscCheck(ascii->sviewer, PETSC_COMM_SELF, PETSC_ERR_ORDER, "SubViewer never obtained from PetscViewer");
761   PetscCheck(ascii->sviewer == *outviewer, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "This PetscViewer did not generate this SubViewer");
762 
763   PetscCall(PetscViewerASCIIPopSynchronized(*outviewer));
764   ascii->sviewer             = NULL;
765   (*outviewer)->ops->destroy = PetscViewerDestroy_ASCII;
766   PetscCall(PetscViewerDestroy(outviewer));
767   PetscCall(PetscViewerASCIIPopSynchronized(viewer));
768   PetscFunctionReturn(PETSC_SUCCESS);
769 }
770 
771 PetscErrorCode PetscViewerView_ASCII(PetscViewer v, PetscViewer viewer)
772 {
773   PetscViewer_ASCII *ascii = (PetscViewer_ASCII *)v->data;
774 
775   PetscFunctionBegin;
776   if (ascii->filename) PetscCall(PetscViewerASCIIPrintf(viewer, "Filename: %s\n", ascii->filename));
777   PetscFunctionReturn(PETSC_SUCCESS);
778 }
779 
780 /*MC
781    PETSCVIEWERASCII - A viewer that prints to stdout or an ASCII file
782 
783   Level: beginner
784 
785 .seealso: [](sec_viewers), `PETSC_VIEWER_STDOUT_()`, `PETSC_VIEWER_STDOUT_SELF`, `PETSC_VIEWER_STDOUT_WORLD`, `PetscViewerCreate()`, `PetscViewerASCIIOpen()`,
786           `PetscViewerMatlabOpen()`, `VecView()`, `DMView()`, `PetscViewerMatlabPutArray()`, `PETSCVIEWERBINARY`, `PETSCVIEWERMATLAB`,
787           `PetscViewerFileSetName()`, `PetscViewerFileSetMode()`, `PetscViewerFormat`, `PetscViewerType`, `PetscViewerSetType()`
788 M*/
789 PETSC_EXTERN PetscErrorCode PetscViewerCreate_ASCII(PetscViewer viewer)
790 {
791   PetscViewer_ASCII *vascii;
792 
793   PetscFunctionBegin;
794   PetscCall(PetscNew(&vascii));
795   viewer->data = (void *)vascii;
796 
797   viewer->ops->destroy          = PetscViewerDestroy_ASCII;
798   viewer->ops->flush            = PetscViewerFlush_ASCII;
799   viewer->ops->getsubviewer     = PetscViewerGetSubViewer_ASCII;
800   viewer->ops->restoresubviewer = PetscViewerRestoreSubViewer_ASCII;
801   viewer->ops->view             = PetscViewerView_ASCII;
802   viewer->ops->read             = PetscViewerASCIIRead;
803 
804   /* defaults to stdout unless set with PetscViewerFileSetName() */
805   vascii->fd        = PETSC_STDOUT;
806   vascii->mode      = FILE_MODE_WRITE;
807   vascii->bviewer   = NULL;
808   vascii->subviewer = NULL;
809   vascii->sviewer   = NULL;
810   vascii->tab       = 0;
811   vascii->tab_store = 0;
812   vascii->filename  = NULL;
813   vascii->closefile = PETSC_TRUE;
814 
815   PetscCall(PetscObjectComposeFunction((PetscObject)viewer, "PetscViewerFileSetName_C", PetscViewerFileSetName_ASCII));
816   PetscCall(PetscObjectComposeFunction((PetscObject)viewer, "PetscViewerFileGetName_C", PetscViewerFileGetName_ASCII));
817   PetscCall(PetscObjectComposeFunction((PetscObject)viewer, "PetscViewerFileGetMode_C", PetscViewerFileGetMode_ASCII));
818   PetscCall(PetscObjectComposeFunction((PetscObject)viewer, "PetscViewerFileSetMode_C", PetscViewerFileSetMode_ASCII));
819   PetscFunctionReturn(PETSC_SUCCESS);
820 }
821 
822 /*@C
823     PetscViewerASCIISynchronizedPrintf - Prints synchronized output to the specified `PETSCVIEWERASCII` file from
824     several processors.  Output of the first processor is followed by that of the
825     second, etc.
826 
827     Not Collective, must call collective `PetscViewerFlush()` to get the results flushed
828 
829     Input Parameters:
830 +   viewer - the `PETSCVIEWERASCII` `PetscViewer`
831 -   format - the usual printf() format string
832 
833     Level: intermediate
834 
835     Notes:
836     You must have previously called `PetscViewerASCIIPushSynchronized()` to allow this routine to be called.
837     Then you can do multiple independent calls to this routine.
838 
839     The actual synchronized print is then done using `PetscViewerFlush()`.
840     `PetscViewerASCIIPopSynchronized()` should be then called if we are already done with the synchronized output
841     to conclude the "synchronized session".
842 
843     So the typical calling sequence looks like
844 .vb
845     PetscViewerASCIIPushSynchronized(viewer);
846     PetscViewerASCIISynchronizedPrintf(viewer, ...);
847     PetscViewerASCIISynchronizedPrintf(viewer, ...);
848     ...
849     PetscViewerFlush(viewer);
850     PetscViewerASCIISynchronizedPrintf(viewer, ...);
851     PetscViewerASCIISynchronizedPrintf(viewer, ...);
852     ...
853     PetscViewerFlush(viewer);
854    PetscViewerASCIIPopSynchronized(viewer);
855 .ve
856 
857     Fortran Note:
858       Can only print a single character* string
859 
860 .seealso: [](sec_viewers), `PetscViewerASCIIPushSynchronized()`, `PetscViewerFlush()`, `PetscViewerASCIIPopSynchronized()`,
861           `PetscSynchronizedPrintf()`, `PetscViewerASCIIPrintf()`, `PetscViewerASCIIOpen()`,
862           `PetscViewerCreate()`, `PetscViewerDestroy()`, `PetscViewerSetType()`
863 @*/
864 PetscErrorCode PetscViewerASCIISynchronizedPrintf(PetscViewer viewer, const char format[], ...)
865 {
866   PetscViewer_ASCII *vascii = (PetscViewer_ASCII *)viewer->data;
867   PetscMPIInt        rank;
868   PetscInt           tab = vascii->tab;
869   MPI_Comm           comm;
870   FILE              *fp;
871   PetscBool          iascii, hasbviewer = PETSC_FALSE;
872 
873   PetscFunctionBegin;
874   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
875   PetscValidCharPointer(format, 2);
876   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
877   PetscCheck(iascii, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Not ASCII PetscViewer");
878   PetscCheck(vascii->allowsynchronized, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "First call PetscViewerASCIIPushSynchronized() to allow this call");
879 
880   PetscCall(PetscObjectGetComm((PetscObject)viewer, &comm));
881   PetscCallMPI(MPI_Comm_rank(comm, &rank));
882 
883   if (vascii->bviewer) {
884     hasbviewer = PETSC_TRUE;
885     if (rank == 0) {
886       vascii = (PetscViewer_ASCII *)vascii->bviewer->data;
887       PetscCall(PetscObjectGetComm((PetscObject)viewer, &comm));
888       PetscCallMPI(MPI_Comm_rank(comm, &rank));
889     }
890   }
891 
892   fp = vascii->fd;
893 
894   if (rank == 0 && !hasbviewer) { /* First processor prints immediately to fp */
895     va_list Argp;
896     /* flush my own messages that I may have queued up */
897     PrintfQueue next = vascii->petsc_printfqueuebase, previous;
898     PetscInt    i;
899     for (i = 0; i < vascii->petsc_printfqueuelength; i++) {
900       PetscCall(PetscFPrintf(comm, fp, "%s", next->string));
901       previous = next;
902       next     = next->next;
903       PetscCall(PetscFree(previous->string));
904       PetscCall(PetscFree(previous));
905     }
906     vascii->petsc_printfqueue       = NULL;
907     vascii->petsc_printfqueuelength = 0;
908 
909     while (tab--) PetscCall(PetscFPrintf(PETSC_COMM_SELF, fp, "  "));
910 
911     va_start(Argp, format);
912     PetscCall((*PetscVFPrintf)(fp, format, Argp));
913     va_end(Argp);
914     PetscCall(PetscFFlush(fp));
915     if (petsc_history) {
916       va_start(Argp, format);
917       PetscCall((*PetscVFPrintf)(petsc_history, format, Argp));
918       va_end(Argp);
919       PetscCall(PetscFFlush(petsc_history));
920     }
921     va_end(Argp);
922   } else { /* other processors add to queue */
923     char       *string;
924     va_list     Argp;
925     size_t      fullLength;
926     PrintfQueue next;
927 
928     PetscCall(PetscNew(&next));
929     if (vascii->petsc_printfqueue) {
930       vascii->petsc_printfqueue->next = next;
931       vascii->petsc_printfqueue       = next;
932     } else {
933       vascii->petsc_printfqueuebase = vascii->petsc_printfqueue = next;
934     }
935     vascii->petsc_printfqueuelength++;
936     next->size = QUEUESTRINGSIZE;
937     PetscCall(PetscCalloc1(next->size, &next->string));
938     string = next->string;
939     tab *= 2;
940     while (tab--) *string++ = ' ';
941     va_start(Argp, format);
942     PetscCall(PetscVSNPrintf(string, next->size - 2 * vascii->tab, format, &fullLength, Argp));
943     va_end(Argp);
944     if (fullLength > (size_t)(next->size - 2 * vascii->tab)) {
945       PetscCall(PetscFree(next->string));
946       next->size = fullLength + 2 * vascii->tab;
947       PetscCall(PetscCalloc1(next->size, &next->string));
948       string = next->string;
949       tab    = 2 * vascii->tab;
950       while (tab--) *string++ = ' ';
951       va_start(Argp, format);
952       PetscCall(PetscVSNPrintf(string, next->size - 2 * vascii->tab, format, NULL, Argp));
953       va_end(Argp);
954     }
955   }
956   PetscFunctionReturn(PETSC_SUCCESS);
957 }
958 
959 /*@C
960    PetscViewerASCIIRead - Reads from a `PETSCVIEWERASCII` file
961 
962    Only MPI rank 0 in the `PetscViewer` may call this
963 
964    Input Parameters:
965 +  viewer - the `PETSCVIEWERASCII` viewer
966 .  data - location to write the data, treated as an array of type indicated by `datatype`
967 .  num - number of items of data to read
968 -  datatype - type of data to read
969 
970    Output Parameter:
971 .  count - number of items of data actually read, or `NULL`
972 
973    Level: beginner
974 
975 .seealso: [](sec_viewers), `PetscViewerASCIIOpen()`, `PetscViewerPushFormat()`, `PetscViewerDestroy()`, `PetscViewerCreate()`, `PetscViewerFileSetMode()`, `PetscViewerFileSetName()`
976           `VecView()`, `MatView()`, `VecLoad()`, `MatLoad()`, `PetscViewerBinaryGetDescriptor()`,
977           `PetscViewerBinaryGetInfoPointer()`, `PetscFileMode`, `PetscViewer`, `PetscViewerBinaryRead()`
978 @*/
979 PetscErrorCode PetscViewerASCIIRead(PetscViewer viewer, void *data, PetscInt num, PetscInt *count, PetscDataType dtype)
980 {
981   PetscViewer_ASCII *vascii = (PetscViewer_ASCII *)viewer->data;
982   FILE              *fd     = vascii->fd;
983   PetscInt           i;
984   int                ret = 0;
985   PetscMPIInt        rank;
986 
987   PetscFunctionBegin;
988   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
989   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank));
990   PetscCheck(rank == 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Can only be called from process 0 in the PetscViewer");
991   for (i = 0; i < num; i++) {
992     if (dtype == PETSC_CHAR) ret = fscanf(fd, "%c", &(((char *)data)[i]));
993     else if (dtype == PETSC_STRING) ret = fscanf(fd, "%s", &(((char *)data)[i]));
994     else if (dtype == PETSC_INT) ret = fscanf(fd, "%" PetscInt_FMT, &(((PetscInt *)data)[i]));
995     else if (dtype == PETSC_ENUM) ret = fscanf(fd, "%d", &(((int *)data)[i]));
996     else if (dtype == PETSC_INT64) ret = fscanf(fd, "%" PetscInt64_FMT, &(((PetscInt64 *)data)[i]));
997     else if (dtype == PETSC_LONG) ret = fscanf(fd, "%ld", &(((long *)data)[i]));
998     else if (dtype == PETSC_FLOAT) ret = fscanf(fd, "%f", &(((float *)data)[i]));
999     else if (dtype == PETSC_DOUBLE) ret = fscanf(fd, "%lg", &(((double *)data)[i]));
1000 #if defined(PETSC_USE_REAL___FLOAT128)
1001     else if (dtype == PETSC___FLOAT128) {
1002       double tmp;
1003       ret                     = fscanf(fd, "%lg", &tmp);
1004       ((__float128 *)data)[i] = tmp;
1005     }
1006 #endif
1007     else
1008       SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Data type %d not supported", (int)dtype);
1009     PetscCheck(ret, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Conversion error for data type %d", (int)dtype);
1010     if (ret < 0) break; /* Proxy for EOF, need to check for it in configure */
1011   }
1012   if (count) *count = i;
1013   else PetscCheck(ret >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Insufficient data, read only %" PetscInt_FMT " < %" PetscInt_FMT " items", i, num);
1014   PetscFunctionReturn(PETSC_SUCCESS);
1015 }
1016