]> git.cworth.org Git - apitrace/blob - cli/cli_pager.cpp
Use less on `apitrace dump`.
[apitrace] / cli / cli_pager.cpp
1 /**************************************************************************
2  *
3  * Copyright 2011 Jose Fonseca
4  * All Rights Reserved.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to deal
8  * in the Software without restriction, including without limitation the rights
9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  * copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22  * THE SOFTWARE.
23  *
24  **************************************************************************/
25
26
27 /*
28  * Pager abstraction.
29  */
30
31
32 #include "cli.hpp"
33
34
35 #if defined(_WIN32)
36
37
38 void
39 pipepager(void) {
40     /* no-op */
41 }
42
43
44 #else /* !defined(_WIN32) */
45
46
47 #include <assert.h>
48 #include <stdlib.h>
49 #include <stdio.h>
50 #include <unistd.h>
51 #include <sys/types.h>
52 #include <sys/stat.h>
53 #include <sys/wait.h>
54 #include <fcntl.h>
55
56
57 static pid_t pid = -1;
58
59
60 /*
61  * Wait for pager process on exit.
62  */
63 static void
64 on_exit(void)
65 {
66         fflush(stdout);
67         fflush(stderr);
68     close(STDOUT_FILENO);
69     close(STDERR_FILENO);
70     waitpid(pid, NULL, 0);
71 }
72
73
74 /*
75  * Wait for page process on signal.
76  */
77 static void
78 on_signal(int sig)
79 {
80     on_exit();
81     signal(sig, SIG_DFL); 
82     raise(sig);
83 }
84
85
86 /*
87  * Spawn a pager process and pipe standard output into it.
88  */
89 void
90 pipepager(void) {
91     if (!isatty(STDOUT_FILENO)) {
92         return;
93     }
94
95     enum {
96         READ_FD  = 0,
97         WRITE_FD = 1
98     };
99
100     int parentToChild[2];
101     int ret;
102     const char *pager;
103
104     ret = pipe(parentToChild);
105     assert(ret == 0);
106
107     pid = fork();
108     switch (pid) {
109     case -1:
110         // failed to fork
111         return;
112
113     case 0:
114         // child
115         ret = dup2(parentToChild[READ_FD], STDIN_FILENO);
116         assert(ret != -1);
117         ret = close(parentToChild[WRITE_FD]);
118         assert(ret == 0);
119
120         pager = getenv("PAGER");
121         if (!pager) {
122             pager = "less";
123         }
124
125         setenv("LESS", "FRXn", 0);
126
127         execlp(pager, pager, NULL);
128
129         // This line should never be reached
130         abort();
131
132     default:
133         // parent
134         ret = close(parentToChild[READ_FD]);
135         assert(ret == 0);
136
137         dup2(parentToChild[WRITE_FD], STDOUT_FILENO);
138         if (isatty(STDERR_FILENO))
139             dup2(parentToChild[WRITE_FD], STDERR_FILENO);
140         close(parentToChild[WRITE_FD]);
141
142         // Ensure we wait for the pager before terminating
143         signal(SIGINT, on_signal);
144         signal(SIGHUP, on_signal);
145         signal(SIGTERM, on_signal);
146         signal(SIGQUIT, on_signal);
147         signal(SIGPIPE, on_signal);
148         atexit(on_exit);
149     }
150 }
151
152
153 #endif /* !defined(_WIN32) */