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