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