]> git.cworth.org Git - apitrace/blob - cli/cli_pager.cpp
common: Add more comments.
[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 <signal.h>
52 #include <sys/types.h>
53 #include <sys/stat.h>
54 #include <sys/wait.h>
55 #include <fcntl.h>
56
57
58 static pid_t pid = -1;
59
60
61 /*
62  * Wait for pager process on exit.
63  */
64 static void
65 on_exit(void)
66 {
67         fflush(stdout);
68         fflush(stderr);
69     close(STDOUT_FILENO);
70     close(STDERR_FILENO);
71     waitpid(pid, NULL, 0);
72 }
73
74
75 /*
76  * Wait for page process on signal.
77  */
78 static void
79 on_signal(int sig)
80 {
81     on_exit();
82     signal(sig, SIG_DFL); 
83     raise(sig);
84 }
85
86
87 /*
88  * Spawn a pager process and pipe standard output into it.
89  */
90 void
91 pipepager(void) {
92     if (!isatty(STDOUT_FILENO)) {
93         return;
94     }
95
96     enum {
97         READ_FD  = 0,
98         WRITE_FD = 1
99     };
100
101     int parentToChild[2];
102     int ret;
103     const char *pager;
104
105     ret = pipe(parentToChild);
106     assert(ret == 0);
107
108     pid = fork();
109     switch (pid) {
110     case -1:
111         // failed to fork
112         return;
113
114     case 0:
115         // child
116         ret = dup2(parentToChild[READ_FD], STDIN_FILENO);
117         assert(ret != -1);
118         ret = close(parentToChild[WRITE_FD]);
119         assert(ret == 0);
120
121         pager = getenv("PAGER");
122         if (!pager) {
123             pager = "less";
124         }
125
126         setenv("LESS", "FRXn", 0);
127
128         execlp(pager, pager, NULL);
129
130         // This line should never be reached
131         abort();
132
133     default:
134         // parent
135         ret = close(parentToChild[READ_FD]);
136         assert(ret == 0);
137
138         dup2(parentToChild[WRITE_FD], STDOUT_FILENO);
139         if (isatty(STDERR_FILENO))
140             dup2(parentToChild[WRITE_FD], STDERR_FILENO);
141         close(parentToChild[WRITE_FD]);
142
143         // Ensure we wait for the pager before terminating
144         signal(SIGINT, on_signal);
145         signal(SIGHUP, on_signal);
146         signal(SIGTERM, on_signal);
147         signal(SIGQUIT, on_signal);
148         signal(SIGPIPE, on_signal);
149         atexit(on_exit);
150     }
151 }
152
153
154 #endif /* !defined(_WIN32) */