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