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