xref: /petsc/src/sys/classes/viewer/impls/ascii/filev.c (revision ab4ee011827fbbb77f789779c813f6db6bb0cbfa)
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 process 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 processor in set 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 processor in set 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 ASCII `PetscViewer`
475 
476     Not Collective, but only first processor in set 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 /* ----------------------------------------------------------------------- */
507 
508 /*@C
509     PetscViewerASCIIPrintf - Prints to a file, only from the first
510     processor in the `PetscViewer` of type `PETSCVIEWERASCII`
511 
512     Not Collective, but only first processor in set has any effect
513 
514     Input Parameters:
515 +    viewer - obtained with `PetscViewerASCIIOpen()`
516 -    format - the usual printf() format string
517 
518     Level: developer
519 
520     Fortran Note:
521     The call sequence is `PetscViewerASCIIPrintf`(PetscViewer, character(*), int ierr) from Fortran.
522     That is, you can only pass a single character string from Fortran.
523 
524 .seealso: [](sec_viewers), `PetscPrintf()`, `PetscSynchronizedPrintf()`, `PetscViewerASCIIOpen()`,
525           `PetscViewerASCIIPushTab()`, `PetscViewerASCIIPopTab()`, `PetscViewerASCIISynchronizedPrintf()`,
526           `PetscViewerCreate()`, `PetscViewerDestroy()`, `PetscViewerSetType()`, `PetscViewerASCIIGetPointer()`, `PetscViewerASCIIPushSynchronized()`
527 @*/
528 PetscErrorCode PetscViewerASCIIPrintf(PetscViewer viewer, const char format[], ...)
529 {
530   PetscViewer_ASCII *ascii = (PetscViewer_ASCII *)viewer->data;
531   PetscMPIInt        rank;
532   PetscInt           tab, intab = ascii->tab;
533   FILE              *fd = ascii->fd;
534   PetscBool          iascii;
535 
536   PetscFunctionBegin;
537   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
538   PetscCheck(!ascii->sviewer, PetscObjectComm((PetscObject)viewer), PETSC_ERR_ARG_WRONGSTATE, "Cannot call with outstanding call to PetscViewerRestoreSubViewer()");
539   PetscValidCharPointer(format, 2);
540   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
541   PetscCheck(iascii, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Not ASCII PetscViewer");
542   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank));
543   if (rank) PetscFunctionReturn(PETSC_SUCCESS);
544 
545   if (ascii->bviewer) { /* pass string up to parent viewer */
546     char   *string;
547     va_list Argp;
548     size_t  fullLength;
549 
550     PetscCall(PetscCalloc1(QUEUESTRINGSIZE, &string));
551     va_start(Argp, format);
552     PetscCall(PetscVSNPrintf(string, QUEUESTRINGSIZE, format, &fullLength, Argp));
553     va_end(Argp);
554     PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%s", string));
555     PetscCall(PetscFree(string));
556   } else { /* write directly to file */
557     va_list Argp;
558     /* flush my own messages that I may have queued up */
559     PrintfQueue next = ascii->petsc_printfqueuebase, previous;
560     PetscInt    i;
561     for (i = 0; i < ascii->petsc_printfqueuelength; i++) {
562       PetscCall(PetscFPrintf(PETSC_COMM_SELF, fd, "%s", next->string));
563       previous = next;
564       next     = next->next;
565       PetscCall(PetscFree(previous->string));
566       PetscCall(PetscFree(previous));
567     }
568     ascii->petsc_printfqueue       = NULL;
569     ascii->petsc_printfqueuelength = 0;
570     tab                            = intab;
571     while (tab--) PetscCall(PetscFPrintf(PETSC_COMM_SELF, fd, "  "));
572 
573     va_start(Argp, format);
574     PetscCall((*PetscVFPrintf)(fd, format, Argp));
575     va_end(Argp);
576     PetscCall(PetscFFlush(fd));
577     if (petsc_history) {
578       tab = intab;
579       while (tab--) PetscCall(PetscFPrintf(PETSC_COMM_SELF, petsc_history, "  "));
580       va_start(Argp, format);
581       PetscCall((*PetscVFPrintf)(petsc_history, format, Argp));
582       va_end(Argp);
583       PetscCall(PetscFFlush(petsc_history));
584     }
585   }
586   PetscFunctionReturn(PETSC_SUCCESS);
587 }
588 
589 /*@C
590      PetscViewerFileSetName - Sets the name of the file the `PetscViewer` uses.
591 
592     Collective
593 
594   Input Parameters:
595 +  viewer - the `PetscViewer`; for example, of type `PETSCVIEWERASCII` or `PETSCVIEWERBINARY`
596 -  name - the name of the file it should use
597 
598     Level: advanced
599 
600 .seealso: [](sec_viewers), `PetscViewerCreate()`, `PetscViewerSetType()`, `PetscViewerASCIIOpen()`, `PetscViewerBinaryOpen()`, `PetscViewerDestroy()`,
601           `PetscViewerASCIIGetPointer()`, `PetscViewerASCIIPrintf()`, `PetscViewerASCIISynchronizedPrintf()`
602 @*/
603 PetscErrorCode PetscViewerFileSetName(PetscViewer viewer, const char name[])
604 {
605   char filename[PETSC_MAX_PATH_LEN];
606 
607   PetscFunctionBegin;
608   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
609   PetscValidCharPointer(name, 2);
610   PetscCall(PetscStrreplace(PetscObjectComm((PetscObject)viewer), name, filename, sizeof(filename)));
611   PetscTryMethod(viewer, "PetscViewerFileSetName_C", (PetscViewer, const char[]), (viewer, filename));
612   PetscFunctionReturn(PETSC_SUCCESS);
613 }
614 
615 /*@C
616      PetscViewerFileGetName - Gets the name of the file the `PetscViewer` uses.
617 
618     Not Collective
619 
620   Input Parameter:
621 .  viewer - the `PetscViewer`
622 
623   Output Parameter:
624 .  name - the name of the file it is using
625 
626     Level: advanced
627 
628 .seealso: [](sec_viewers), `PetscViewerCreate()`, `PetscViewerSetType()`, `PetscViewerASCIIOpen()`, `PetscViewerBinaryOpen()`, `PetscViewerFileSetName()`
629 @*/
630 PetscErrorCode PetscViewerFileGetName(PetscViewer viewer, const char **name)
631 {
632   PetscFunctionBegin;
633   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
634   PetscValidPointer(name, 2);
635   PetscUseMethod(viewer, "PetscViewerFileGetName_C", (PetscViewer, const char **), (viewer, name));
636   PetscFunctionReturn(PETSC_SUCCESS);
637 }
638 
639 PetscErrorCode PetscViewerFileGetName_ASCII(PetscViewer viewer, const char **name)
640 {
641   PetscViewer_ASCII *vascii = (PetscViewer_ASCII *)viewer->data;
642 
643   PetscFunctionBegin;
644   *name = vascii->filename;
645   PetscFunctionReturn(PETSC_SUCCESS);
646 }
647 
648 #include <errno.h>
649 PetscErrorCode PetscViewerFileSetName_ASCII(PetscViewer viewer, const char name[])
650 {
651   size_t             len;
652   char               fname[PETSC_MAX_PATH_LEN], *gz = NULL;
653   PetscViewer_ASCII *vascii = (PetscViewer_ASCII *)viewer->data;
654   PetscBool          isstderr, isstdout;
655   PetscMPIInt        rank;
656 
657   PetscFunctionBegin;
658   PetscCall(PetscViewerFileClose_ASCII(viewer));
659   if (!name) PetscFunctionReturn(PETSC_SUCCESS);
660   PetscCall(PetscStrallocpy(name, &vascii->filename));
661 
662   /* Is this file to be compressed */
663   vascii->storecompressed = PETSC_FALSE;
664 
665   PetscCall(PetscStrstr(vascii->filename, ".gz", &gz));
666   if (gz) {
667     PetscCall(PetscStrlen(gz, &len));
668     if (len == 3) {
669       PetscCheck(vascii->mode == FILE_MODE_WRITE, PetscObjectComm((PetscObject)viewer), PETSC_ERR_SUP, "Cannot open ASCII PetscViewer file that is compressed; uncompress it manually first");
670       *gz                     = 0;
671       vascii->storecompressed = PETSC_TRUE;
672     }
673   }
674   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank));
675   if (rank == 0) {
676     PetscCall(PetscStrcmp(name, "stderr", &isstderr));
677     PetscCall(PetscStrcmp(name, "stdout", &isstdout));
678     /* empty filename means stdout */
679     if (name[0] == 0) isstdout = PETSC_TRUE;
680     if (isstderr) vascii->fd = PETSC_STDERR;
681     else if (isstdout) vascii->fd = PETSC_STDOUT;
682     else {
683       PetscCall(PetscFixFilename(name, fname));
684       switch (vascii->mode) {
685       case FILE_MODE_READ:
686         vascii->fd = fopen(fname, "r");
687         break;
688       case FILE_MODE_WRITE:
689         vascii->fd = fopen(fname, "w");
690         break;
691       case FILE_MODE_APPEND:
692         vascii->fd = fopen(fname, "a");
693         break;
694       case FILE_MODE_UPDATE:
695         vascii->fd = fopen(fname, "r+");
696         if (!vascii->fd) vascii->fd = fopen(fname, "w+");
697         break;
698       case FILE_MODE_APPEND_UPDATE:
699         /* I really want a file which is opened at the end for updating,
700            not a+, which opens at the beginning, but makes writes at the end.
701         */
702         vascii->fd = fopen(fname, "r+");
703         if (!vascii->fd) vascii->fd = fopen(fname, "w+");
704         else {
705           int ret = fseek(vascii->fd, 0, SEEK_END);
706           PetscCheck(!ret, PETSC_COMM_SELF, PETSC_ERR_LIB, "fseek() failed with error code %d", ret);
707         }
708         break;
709       default:
710         SETERRQ(PetscObjectComm((PetscObject)viewer), PETSC_ERR_SUP, "Unsupported file mode %s", PetscFileModes[vascii->mode]);
711       }
712       PetscCheck(vascii->fd, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Cannot open PetscViewer file: %s due to \"%s\"", fname, strerror(errno));
713     }
714   }
715 #if defined(PETSC_USE_LOG)
716   PetscCall(PetscLogObjectState((PetscObject)viewer, "File: %s", name));
717 #endif
718   PetscFunctionReturn(PETSC_SUCCESS);
719 }
720 
721 PetscErrorCode PetscViewerGetSubViewer_ASCII(PetscViewer viewer, MPI_Comm subcomm, PetscViewer *outviewer)
722 {
723   PetscViewer_ASCII *vascii = (PetscViewer_ASCII *)viewer->data, *ovascii;
724 
725   PetscFunctionBegin;
726   PetscCall(PetscViewerASCIIPushSynchronized(viewer));
727   PetscCheck(!vascii->sviewer, PETSC_COMM_SELF, PETSC_ERR_ORDER, "SubViewer already obtained from PetscViewer and not restored");
728   /*
729      The following line is a bug; it does another PetscViewerASCIIPushSynchronized() on viewer, but if it is removed the code won't work
730      because it relies on this behavior in other places. In particular this line causes the synchronized flush to occur when the viewer is destroyed
731      (since the count never gets to zero) in some examples this displays information that otherwise would be lost
732 
733      This code also means another call to PetscViewerASCIIPopSynchronized() must be made after the PetscViewerRestoreSubViewer(), see, for example,
734      PCView_GASM().
735   */
736   PetscCall(PetscViewerASCIIPushSynchronized(viewer));
737   PetscCall(PetscViewerCreate(subcomm, outviewer));
738   PetscCall(PetscViewerSetType(*outviewer, PETSCVIEWERASCII));
739   PetscCall(PetscViewerASCIIPushSynchronized(*outviewer));
740   ovascii            = (PetscViewer_ASCII *)(*outviewer)->data;
741   ovascii->fd        = vascii->fd;
742   ovascii->tab       = vascii->tab;
743   ovascii->closefile = PETSC_FALSE;
744 
745   vascii->sviewer                                      = *outviewer;
746   (*outviewer)->format                                 = viewer->format;
747   ((PetscViewer_ASCII *)((*outviewer)->data))->bviewer = viewer;
748   (*outviewer)->ops->destroy                           = PetscViewerDestroy_ASCII_SubViewer;
749   PetscFunctionReturn(PETSC_SUCCESS);
750 }
751 
752 PetscErrorCode PetscViewerRestoreSubViewer_ASCII(PetscViewer viewer, MPI_Comm comm, PetscViewer *outviewer)
753 {
754   PetscViewer_ASCII *ascii = (PetscViewer_ASCII *)viewer->data;
755 
756   PetscFunctionBegin;
757   PetscCheck(ascii->sviewer, PETSC_COMM_SELF, PETSC_ERR_ORDER, "SubViewer never obtained from PetscViewer");
758   PetscCheck(ascii->sviewer == *outviewer, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "This PetscViewer did not generate this SubViewer");
759 
760   PetscCall(PetscViewerASCIIPopSynchronized(*outviewer));
761   ascii->sviewer             = NULL;
762   (*outviewer)->ops->destroy = PetscViewerDestroy_ASCII;
763   PetscCall(PetscViewerDestroy(outviewer));
764   PetscCall(PetscViewerASCIIPopSynchronized(viewer));
765   PetscFunctionReturn(PETSC_SUCCESS);
766 }
767 
768 PetscErrorCode PetscViewerView_ASCII(PetscViewer v, PetscViewer viewer)
769 {
770   PetscViewer_ASCII *ascii = (PetscViewer_ASCII *)v->data;
771 
772   PetscFunctionBegin;
773   if (ascii->filename) PetscCall(PetscViewerASCIIPrintf(viewer, "Filename: %s\n", ascii->filename));
774   PetscFunctionReturn(PETSC_SUCCESS);
775 }
776 
777 /*MC
778    PETSCVIEWERASCII - A viewer that prints to stdout or an ASCII file
779 
780   Level: beginner
781 
782 .seealso: [](sec_viewers), `PETSC_VIEWER_STDOUT_()`, `PETSC_VIEWER_STDOUT_SELF`, `PETSC_VIEWER_STDOUT_WORLD`, `PetscViewerCreate()`, `PetscViewerASCIIOpen()`,
783           `PetscViewerMatlabOpen()`, `VecView()`, `DMView()`, `PetscViewerMatlabPutArray()`, `PETSCVIEWERBINARY`, `PETSCVIEWERMATLAB`,
784           `PetscViewerFileSetName()`, `PetscViewerFileSetMode()`, `PetscViewerFormat`, `PetscViewerType`, `PetscViewerSetType()`
785 M*/
786 PETSC_EXTERN PetscErrorCode PetscViewerCreate_ASCII(PetscViewer viewer)
787 {
788   PetscViewer_ASCII *vascii;
789 
790   PetscFunctionBegin;
791   PetscCall(PetscNew(&vascii));
792   viewer->data = (void *)vascii;
793 
794   viewer->ops->destroy          = PetscViewerDestroy_ASCII;
795   viewer->ops->flush            = PetscViewerFlush_ASCII;
796   viewer->ops->getsubviewer     = PetscViewerGetSubViewer_ASCII;
797   viewer->ops->restoresubviewer = PetscViewerRestoreSubViewer_ASCII;
798   viewer->ops->view             = PetscViewerView_ASCII;
799   viewer->ops->read             = PetscViewerASCIIRead;
800 
801   /* defaults to stdout unless set with PetscViewerFileSetName() */
802   vascii->fd        = PETSC_STDOUT;
803   vascii->mode      = FILE_MODE_WRITE;
804   vascii->bviewer   = NULL;
805   vascii->subviewer = NULL;
806   vascii->sviewer   = NULL;
807   vascii->tab       = 0;
808   vascii->tab_store = 0;
809   vascii->filename  = NULL;
810   vascii->closefile = PETSC_TRUE;
811 
812   PetscCall(PetscObjectComposeFunction((PetscObject)viewer, "PetscViewerFileSetName_C", PetscViewerFileSetName_ASCII));
813   PetscCall(PetscObjectComposeFunction((PetscObject)viewer, "PetscViewerFileGetName_C", PetscViewerFileGetName_ASCII));
814   PetscCall(PetscObjectComposeFunction((PetscObject)viewer, "PetscViewerFileGetMode_C", PetscViewerFileGetMode_ASCII));
815   PetscCall(PetscObjectComposeFunction((PetscObject)viewer, "PetscViewerFileSetMode_C", PetscViewerFileSetMode_ASCII));
816   PetscFunctionReturn(PETSC_SUCCESS);
817 }
818 
819 /*@C
820     PetscViewerASCIISynchronizedPrintf - Prints synchronized output to the specified file from
821     several processors.  Output of the first processor is followed by that of the
822     second, etc.
823 
824     Not Collective, must call collective `PetscViewerFlush()` to get the results out
825 
826     Input Parameters:
827 +   viewer - the `PETSCVIEWERASCII` `PetscViewer`
828 -   format - the usual printf() format string
829 
830     Level: intermediate
831 
832     Notes:
833     You must have previously called `PetscViewerASCIIPushSynchronized()` to allow this routine to be called.
834     Then you can do multiple independent calls to this routine.
835 
836     The actual synchronized print is then done using `PetscViewerFlush()`.
837     `PetscViewerASCIIPopSynchronized()` should be then called if we are already done with the synchronized output
838     to conclude the "synchronized session".
839 
840     So the typical calling sequence looks like
841 .vb
842     PetscViewerASCIIPushSynchronized(viewer);
843     PetscViewerASCIISynchronizedPrintf(viewer, ...);
844     PetscViewerASCIISynchronizedPrintf(viewer, ...);
845     ...
846     PetscViewerFlush(viewer);
847     PetscViewerASCIISynchronizedPrintf(viewer, ...);
848     PetscViewerASCIISynchronizedPrintf(viewer, ...);
849     ...
850     PetscViewerFlush(viewer);
851    PetscViewerASCIIPopSynchronized(viewer);
852 .ve
853 
854     Fortran Note:
855       Can only print a single character* string
856 
857 .seealso: [](sec_viewers), `PetscViewerASCIIPushSynchronized()`, `PetscViewerFlush()`, `PetscViewerASCIIPopSynchronized()`,
858           `PetscSynchronizedPrintf()`, `PetscViewerASCIIPrintf()`, `PetscViewerASCIIOpen()`,
859           `PetscViewerCreate()`, `PetscViewerDestroy()`, `PetscViewerSetType()`
860 @*/
861 PetscErrorCode PetscViewerASCIISynchronizedPrintf(PetscViewer viewer, const char format[], ...)
862 {
863   PetscViewer_ASCII *vascii = (PetscViewer_ASCII *)viewer->data;
864   PetscMPIInt        rank;
865   PetscInt           tab = vascii->tab;
866   MPI_Comm           comm;
867   FILE              *fp;
868   PetscBool          iascii, hasbviewer = PETSC_FALSE;
869 
870   PetscFunctionBegin;
871   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
872   PetscValidCharPointer(format, 2);
873   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
874   PetscCheck(iascii, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Not ASCII PetscViewer");
875   PetscCheck(vascii->allowsynchronized, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "First call PetscViewerASCIIPushSynchronized() to allow this call");
876 
877   PetscCall(PetscObjectGetComm((PetscObject)viewer, &comm));
878   PetscCallMPI(MPI_Comm_rank(comm, &rank));
879 
880   if (vascii->bviewer) {
881     hasbviewer = PETSC_TRUE;
882     if (rank == 0) {
883       vascii = (PetscViewer_ASCII *)vascii->bviewer->data;
884       PetscCall(PetscObjectGetComm((PetscObject)viewer, &comm));
885       PetscCallMPI(MPI_Comm_rank(comm, &rank));
886     }
887   }
888 
889   fp = vascii->fd;
890 
891   if (rank == 0 && !hasbviewer) { /* First processor prints immediately to fp */
892     va_list Argp;
893     /* flush my own messages that I may have queued up */
894     PrintfQueue next = vascii->petsc_printfqueuebase, previous;
895     PetscInt    i;
896     for (i = 0; i < vascii->petsc_printfqueuelength; i++) {
897       PetscCall(PetscFPrintf(comm, fp, "%s", next->string));
898       previous = next;
899       next     = next->next;
900       PetscCall(PetscFree(previous->string));
901       PetscCall(PetscFree(previous));
902     }
903     vascii->petsc_printfqueue       = NULL;
904     vascii->petsc_printfqueuelength = 0;
905 
906     while (tab--) PetscCall(PetscFPrintf(PETSC_COMM_SELF, fp, "  "));
907 
908     va_start(Argp, format);
909     PetscCall((*PetscVFPrintf)(fp, format, Argp));
910     va_end(Argp);
911     PetscCall(PetscFFlush(fp));
912     if (petsc_history) {
913       va_start(Argp, format);
914       PetscCall((*PetscVFPrintf)(petsc_history, format, Argp));
915       va_end(Argp);
916       PetscCall(PetscFFlush(petsc_history));
917     }
918     va_end(Argp);
919   } else { /* other processors add to queue */
920     char       *string;
921     va_list     Argp;
922     size_t      fullLength;
923     PrintfQueue next;
924 
925     PetscCall(PetscNew(&next));
926     if (vascii->petsc_printfqueue) {
927       vascii->petsc_printfqueue->next = next;
928       vascii->petsc_printfqueue       = next;
929     } else {
930       vascii->petsc_printfqueuebase = vascii->petsc_printfqueue = next;
931     }
932     vascii->petsc_printfqueuelength++;
933     next->size = QUEUESTRINGSIZE;
934     PetscCall(PetscCalloc1(next->size, &next->string));
935     string = next->string;
936     tab *= 2;
937     while (tab--) *string++ = ' ';
938     va_start(Argp, format);
939     PetscCall(PetscVSNPrintf(string, next->size - 2 * vascii->tab, format, &fullLength, Argp));
940     va_end(Argp);
941     if (fullLength > (size_t)(next->size - 2 * vascii->tab)) {
942       PetscCall(PetscFree(next->string));
943       next->size = fullLength + 2 * vascii->tab;
944       PetscCall(PetscCalloc1(next->size, &next->string));
945       string = next->string;
946       tab    = 2 * vascii->tab;
947       while (tab--) *string++ = ' ';
948       va_start(Argp, format);
949       PetscCall(PetscVSNPrintf(string, next->size - 2 * vascii->tab, format, NULL, Argp));
950       va_end(Argp);
951     }
952   }
953   PetscFunctionReturn(PETSC_SUCCESS);
954 }
955 
956 /*@C
957    PetscViewerASCIIRead - Reads from a ASCII file
958 
959    Only process 0 in the `PetscViewer` may call this
960 
961    Input Parameters:
962 +  viewer - the `PETSCVIEWERASCII` viewer
963 .  data - location to write the data
964 .  num - number of items of data to read
965 -  datatype - type of data to read
966 
967    Output Parameter:
968 .  count - number of items of data actually read, or `NULL`
969 
970    Level: beginner
971 
972 .seealso: [](sec_viewers), `PetscViewerASCIIOpen()`, `PetscViewerPushFormat()`, `PetscViewerDestroy()`, `PetscViewerCreate()`, `PetscViewerFileSetMode()`, `PetscViewerFileSetName()`
973           `VecView()`, `MatView()`, `VecLoad()`, `MatLoad()`, `PetscViewerBinaryGetDescriptor()`,
974           `PetscViewerBinaryGetInfoPointer()`, `PetscFileMode`, `PetscViewer`, `PetscViewerBinaryRead()`
975 @*/
976 PetscErrorCode PetscViewerASCIIRead(PetscViewer viewer, void *data, PetscInt num, PetscInt *count, PetscDataType dtype)
977 {
978   PetscViewer_ASCII *vascii = (PetscViewer_ASCII *)viewer->data;
979   FILE              *fd     = vascii->fd;
980   PetscInt           i;
981   int                ret = 0;
982   PetscMPIInt        rank;
983 
984   PetscFunctionBegin;
985   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
986   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank));
987   PetscCheck(rank == 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Can only be called from process 0 in the PetscViewer");
988   for (i = 0; i < num; i++) {
989     if (dtype == PETSC_CHAR) ret = fscanf(fd, "%c", &(((char *)data)[i]));
990     else if (dtype == PETSC_STRING) ret = fscanf(fd, "%s", &(((char *)data)[i]));
991     else if (dtype == PETSC_INT) ret = fscanf(fd, "%" PetscInt_FMT, &(((PetscInt *)data)[i]));
992     else if (dtype == PETSC_ENUM) ret = fscanf(fd, "%d", &(((int *)data)[i]));
993     else if (dtype == PETSC_INT64) ret = fscanf(fd, "%" PetscInt64_FMT, &(((PetscInt64 *)data)[i]));
994     else if (dtype == PETSC_LONG) ret = fscanf(fd, "%ld", &(((long *)data)[i]));
995     else if (dtype == PETSC_FLOAT) ret = fscanf(fd, "%f", &(((float *)data)[i]));
996     else if (dtype == PETSC_DOUBLE) ret = fscanf(fd, "%lg", &(((double *)data)[i]));
997 #if defined(PETSC_USE_REAL___FLOAT128)
998     else if (dtype == PETSC___FLOAT128) {
999       double tmp;
1000       ret                     = fscanf(fd, "%lg", &tmp);
1001       ((__float128 *)data)[i] = tmp;
1002     }
1003 #endif
1004     else
1005       SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Data type %d not supported", (int)dtype);
1006     PetscCheck(ret, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Conversion error for data type %d", (int)dtype);
1007     if (ret < 0) break; /* Proxy for EOF, need to check for it in configure */
1008   }
1009   if (count) *count = i;
1010   else PetscCheck(ret >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Insufficient data, read only %" PetscInt_FMT " < %" PetscInt_FMT " items", i, num);
1011   PetscFunctionReturn(PETSC_SUCCESS);
1012 }
1013