chiark / gitweb /
Fix signal handlers so they don't corrupt `errno'.
[sw-tools] / src / pres_curses.c
1 /* -*-c-*-
2  *
3  * $Id: pres_curses.c,v 1.2 1999/06/24 15:51:16 mdw Exp $
4  *
5  * Curses-based output presentation
6  *
7  * (c) 1999 EBI
8  */
9
10 /*----- Licensing notice --------------------------------------------------* 
11  *
12  * This file is part of sw-tools.
13  *
14  * sw-tools is free software; you can redistribute it and/or modify
15  * it under the terms of the GNU General Public License as published by
16  * the Free Software Foundation; either version 2 of the License, or
17  * (at your option) any later version.
18  * 
19  * sw-tools is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU General Public License for more details.
23  * 
24  * You should have received a copy of the GNU General Public License
25  * along with sw-tools; if not, write to the Free Software Foundation,
26  * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
27  */
28
29 /*----- Revision history --------------------------------------------------* 
30  *
31  * $Log: pres_curses.c,v $
32  * Revision 1.2  1999/06/24 15:51:16  mdw
33  * Fix signal handlers so they don't corrupt `errno'.
34  *
35  * Revision 1.1.1.1  1999/06/02 16:53:35  mdw
36  * Initial import.
37  *
38  */
39
40 /*----- Header files ------------------------------------------------------*/
41
42 #include "config.h"
43 #ifdef HAVE_CURSES
44
45 #include <errno.h>
46 #include <signal.h>
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <string.h>
50
51 #include <sys/types.h>
52 #include <unistd.h>
53
54 #if defined(HAVE_NCURSES_H)
55 #  include <ncurses.h>
56 #elif defined(HAVE_NCURSES_NCURSES_H)
57 #  include <ncurses/ncurses.h>
58 #elif defined(HAVE_CURSES_H)
59 #  include <curses.h>
60 #else
61 #  error "Where's your <curses.h> header?"
62 #endif
63 #include <term.h>
64
65 #include <mLib/alloc.h>
66 #include <mLib/report.h>
67
68 #include "sw.h"
69 #include "sw_arch.h"
70 #include "pres_curses.h"
71
72 #ifndef SIGWINCH
73 #  undef HAVE_WRESIZE
74 #endif
75
76 /*----- Data structures ---------------------------------------------------*/
77
78 typedef struct cwin {
79   struct cwin *next;
80   WINDOW *w;
81   int top;
82   int height;
83   WINDOW *s;
84   archent *e;
85 } cwin;
86
87 /*----- Static variables --------------------------------------------------*/
88
89 static cwin *cwins = 0;
90 static int nwins = 0;
91
92 /*----- Main code ---------------------------------------------------------*/
93
94 /* --- @sizes@ --- *
95  *
96  * Arguments:   ---
97  *
98  * Returns:     ---
99  *
100  * Use:         Calculates window sizes for all the windows.  The heights are
101  *              determined in a way which doesn't allow rounding errors to be
102  *              an issue (although there will be up to a line's height
103  *              difference between two windows).  No actual changing of
104  *              curses structures is done.
105  */
106
107 static void sizes(void)
108 {
109   cwin *c;
110   int t = 0, h = LINES, w = nwins;
111
112   for (c = cwins; c; c = c->next) {
113     int a = h / w;
114     c->top = t;
115     c->height = a - 1;
116     t += a;
117     h -= a;
118     w--;
119   }
120 }
121
122 /* --- @sig_tstp@ --- */
123
124 #ifdef SIGTSTP
125 static void sig_tstp(int s)
126 {
127   int e = errno;
128   endwin();
129   errno = e;
130   raise(SIGSTOP);
131 }
132 #endif
133
134 /* --- @sig_cont@ --- */
135
136 #ifdef SIGTSTP
137 static void sig_cont(int s)
138 {
139   int e = errno;
140   wrefresh(curscr);
141   errno = e;
142 }
143 #endif
144
145 /* --- @sig_winch@ --- */
146
147 #ifdef HAVE_WRESIZE
148
149 static void sig_winch(int s)
150 {
151   cwin *c;
152   int e = errno;
153
154   endwin();
155   refresh();
156   sizes();
157   for (c = cwins; c; c = c->next) {
158     mvwin(c->w, c->top, 0);
159     wresize(c->w, c->height, COLS);
160     mvwin(c->s, c->top + c->height, 0);
161     wnoutrefresh(c->w);
162     wnoutrefresh(c->s);
163   }
164   doupdate();
165   errno = e;
166 }
167
168 #endif
169
170 /* --- @curses_ok@ --- */
171
172 int curses_ok(void)
173 {
174   if (!isatty(STDOUT_FILENO)) {
175     moan("can't use curses: stdout isn't a terminal");
176     return (0);
177   }
178   if (setupterm(0, STDOUT_FILENO, 0) == ERR) {
179     moan("can't use curses: couldn't read terminfo");
180     return (0);
181   }
182   if (!tigetstr("cup")) {
183     moan("can't use curses: terminal insufficiently winning");
184     return (0);
185   }
186   return (1);
187 }
188
189 /* --- @curses_init@ --- */
190
191 int curses_init(archcons *a)
192 {
193   cwin **cc = &cwins, *c;
194
195   /* --- Allocate my window structures --- */
196
197   nwins = 0;
198   for (; a; a = a->cdr) {
199     archent *e = a->car;
200     if (!e->r)
201       continue;
202     c = xmalloc(sizeof(cwin));
203     e->pres = c;
204     c->w = 0;
205     c->e = e;
206     nwins++;
207     *cc = c;
208     cc = &c->next;
209   }
210   *cc = 0;
211
212   /* --- Haul curses up by its naughty bits --- */
213
214   initscr();
215   keypad(stdscr, TRUE);
216   cbreak();
217   noecho();
218   nonl();
219   def_prog_mode();
220
221   /* --- Grind through everything setting up windows --- */
222
223   sizes();
224   for (c = cwins; c; c = c->next) {
225     if ((c->w = newwin(c->height, COLS, c->top, 0)) == 0 ||
226         (c->s = newwin(1, COLS, c->top + c->height, 0)) == 0)
227       goto fail_0;
228     scrollok(c->w, TRUE);
229     leaveok(c->w, TRUE);
230     leaveok(c->s, TRUE);
231     wbkgdset(c->s, A_STANDOUT);
232     werase(c->s);
233     mvwprintw(c->s, 0, 0, "  %s  [running]\n", c->e->arch);
234     wnoutrefresh(c->w);
235     wnoutrefresh(c->s);
236   }
237   doupdate();
238
239 #ifdef HAVE_WRESIZE
240   signal(SIGWINCH, sig_winch);
241 #endif
242 #ifdef SIGTSTP
243   signal(SIGTSTP, sig_tstp);
244   signal(SIGCONT, sig_cont);
245 #endif
246   return (0);
247
248 fail_0:
249   c = cwins;
250   while (c) {
251     cwin *cc = c->next;
252     if (c->w)
253       delwin(c->w);
254     if (c->s)
255       delwin(c->s);
256     free(c);
257     c = cc;
258   }
259   endwin();
260   return (-1);
261 }
262
263 /* --- @curses_output@ --- */
264
265 void curses_output(archent *e, const char *p, size_t sz)
266 {
267   cwin *c = e->pres;
268   while (sz) {
269     waddch(c->w, *p);
270     p++;
271     sz--;
272   }
273   wrefresh(c->w);
274 }
275
276 /* --- @curses_close@ --- */
277
278 void curses_close(archent *e, int ok)
279 {
280   cwin *c = e->pres;
281   mvwprintw(c->s, 0, 0, "  %s [%s]\n", e->arch, ok ? "finished" : "failed");
282   wrefresh(c->s);
283 }
284
285 /* --- @curses_done@ --- */
286
287 void curses_done(archcons *a)
288 {
289   if (opt_flags & optFlag_beep) {
290     beep();
291     doupdate();
292   }
293   wgetch(cwins->w);
294   cwins = 0;
295   for (; a; a = a->cdr) {
296     archent *e = a->car;
297     cwin *c = e->pres;
298     delwin(c->w);
299     delwin(c->s);
300     free(c);
301   }
302   curses_abort(0);
303 }
304
305 /* --- @curses_abort@ --- */
306
307 void curses_abort(archcons *a)
308 {
309 #ifdef HAVE_WRESIZE
310   signal(SIGWINCH, SIG_DFL);
311 #endif
312 #ifdef SIGTSTP
313   signal(SIGTSTP, SIG_DFL);
314   signal(SIGCONT, SIG_DFL);
315 #endif
316   endwin();
317 }
318
319 /*----- That's all, folks -------------------------------------------------*/
320
321 #else
322   int pres_curses__built = 1;
323 #endif