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