source: trunk/third/ispell/term.c @ 22599

Revision 22599, 15.2 KB checked in by ghudson, 18 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r22598, which included commits to RCS files with non-trunk default branches.
Line 
1#ifndef lint
2static char Rcs_Id[] =
3    "$Id: term.c,v 1.1.1.2 2007-02-01 19:50:05 ghudson Exp $";
4#endif
5
6/*
7 * term.c - deal with termcap, and unix terminal mode settings
8 *
9 * Pace Willisson, 1983
10 *
11 * Copyright 1987, 1988, 1989, 1992, 1993, 1999, 2001, 2005, Geoff Kuenning,
12 * Claremont, CA.
13 * All rights reserved.
14 *
15 * Redistribution and use in source and binary forms, with or without
16 * modification, are permitted provided that the following conditions
17 * are met:
18 *
19 * 1. Redistributions of source code must retain the above copyright
20 *    notice, this list of conditions and the following disclaimer.
21 * 2. Redistributions in binary form must reproduce the above copyright
22 *    notice, this list of conditions and the following disclaimer in the
23 *    documentation and/or other materials provided with the distribution.
24 * 3. All modifications to the source code must be clearly marked as
25 *    such.  Binary redistributions based on modified source code
26 *    must be clearly marked as modified versions in the documentation
27 *    and/or other materials provided with the distribution.
28 * 4. The code that causes the 'ispell -v' command to display a prominent
29 *    link to the official ispell Web site may not be removed.
30 * 5. The name of Geoff Kuenning may not be used to endorse or promote
31 *    products derived from this software without specific prior
32 *    written permission.
33 *
34 * THIS SOFTWARE IS PROVIDED BY GEOFF KUENNING AND CONTRIBUTORS ``AS IS'' AND
35 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
36 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
37 * ARE DISCLAIMED.  IN NO EVENT SHALL GEOFF KUENNING OR CONTRIBUTORS BE LIABLE
38 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
39 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
40 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
41 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
42 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
43 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 * SUCH DAMAGE.
45 */
46
47/*
48 * $Log: not supported by cvs2svn $
49 * Revision 1.54  2005/04/14 23:11:36  geoff
50 * Correctly handle control-Z, including resetting the terminal.  The
51 * only remaining problem is that the screen isn't automatically
52 * refreshed. (Doing the latter would either require major changes to
53 * make the screen-refresh code callable from the signal handler, or
54 * fixing GETKEYSTROKE to fail on signals.  That's probably not hugely
55 * hard but doing it portably probably is.)
56 *
57 * Revision 1.53  2005/04/14 14:38:23  geoff
58 * Update license.  Rename move/erase to avoid library conflicts.
59 *
60 * Revision 1.52  2001/09/06 00:30:28  geoff
61 * Many changes from Eli Zaretskii to support DJGPP compilation.
62 *
63 * Revision 1.51  2001/07/25 21:51:46  geoff
64 * Minor license update.
65 *
66 * Revision 1.50  2001/07/23 20:24:04  geoff
67 * Update the copyright and the license.
68 *
69 * Revision 1.49  1999/01/07 01:22:53  geoff
70 * Update the copyright.
71 *
72 * Revision 1.48  1994/10/25  05:46:11  geoff
73 * Fix a couple of places where ifdefs were omitted, though apparently
74 * harmlessly.
75 *
76 * Revision 1.47  1994/09/01  06:06:32  geoff
77 * Change erasechar/killchar to uerasechar/ukillchar to avoid
78 * shared-library problems on HP systems.
79 *
80 * Revision 1.46  1994/01/25  07:12:11  geoff
81 * Get rid of all old RCS log lines in preparation for the 3.1 release.
82 *
83 */
84
85#include "config.h"
86#include "ispell.h"
87#include "proto.h"
88#include "msgs.h"
89#ifdef USG
90#include <termio.h>
91#else
92#ifndef __DJGPP__
93#include <sgtty.h>
94#endif
95#endif
96#include <signal.h>
97
98void            ierase P ((void));
99void            imove P ((int row, int col));
100void            inverse P ((void));
101void            normal P ((void));
102void            backup P ((void));
103static int      iputch P ((int c));
104void            terminit P ((void));
105SIGNAL_TYPE     done P ((int signo));
106#ifdef SIGTSTP
107static SIGNAL_TYPE onstop P ((int signo));
108#endif /* SIGTSTP */
109void            stop P ((void));
110int             shellescape P ((char * buf));
111#ifdef USESH
112void            shescape P ((char * buf));
113#endif /* USESH */
114
115static int      termchanged = 0;
116
117#ifdef __DJGPP__
118#include "pc/djterm.c"
119#endif
120
121void ierase ()
122    {
123
124    if (cl)
125        tputs (cl, li, iputch);
126    else
127        {
128        if (ho)
129            tputs (ho, 100, iputch);
130        else if (cm)
131            tputs (tgoto (cm, 0, 0), 100, iputch);
132        tputs (cd, li, iputch);
133        }
134    }
135
136void imove (row, col)
137    int         row;
138    int         col;
139    {
140    tputs (tgoto (cm, col, row), 100, iputch);
141    }
142
143void inverse ()
144    {
145    tputs (so, 10, iputch);
146    }
147
148void normal ()
149    {
150    tputs (se, 10, iputch);
151    }
152
153void backup ()
154    {
155    if (BC)
156        tputs (BC, 1, iputch);
157    else
158        (void) putchar ('\b');
159    }
160
161static int iputch (c)
162    int                 c;
163    {
164
165    return putchar (c);
166    }
167
168#ifdef USG
169static struct termio    sbuf;
170static struct termio    osbuf;
171#else
172static struct sgttyb    sbuf;
173static struct sgttyb    osbuf;
174#ifdef TIOCSLTC
175static struct ltchars   ltc;
176static struct ltchars   oltc;
177#endif
178#endif
179static SIGNAL_TYPE      (*oldint) ();
180static SIGNAL_TYPE      (*oldterm) ();
181#ifdef SIGTSTP
182static SIGNAL_TYPE      (*oldttin) ();
183static SIGNAL_TYPE      (*oldttou) ();
184static SIGNAL_TYPE      (*oldtstp) ();
185#endif
186
187void terminit ()
188    {
189#ifdef TIOCPGRP
190    int                 tpgrp;
191#else
192#ifdef TIOCGPGRP
193    int                 tpgrp;
194#endif
195#endif
196#ifdef TIOCGWINSZ
197    struct winsize      wsize;
198#endif /* TIOCGWINSZ */
199
200    tgetent (termcap, getenv ("TERM"));
201    termptr = termstr;
202    BC = tgetstr ("bc", &termptr);
203    cd = tgetstr ("cd", &termptr);
204    cl = tgetstr ("cl", &termptr);
205    cm = tgetstr ("cm", &termptr);
206    ho = tgetstr ("ho", &termptr);
207    nd = tgetstr ("nd", &termptr);
208    so = tgetstr ("so", &termptr);      /* inverse video on */
209    se = tgetstr ("se", &termptr);      /* inverse video off */
210    if ((sg = tgetnum ("sg")) < 0)      /* space taken by so/se */
211        sg = 0;
212    ti = tgetstr ("ti", &termptr);      /* terminal initialization */
213    te = tgetstr ("te", &termptr);      /* terminal termination */
214    co = tgetnum ("co");
215    li = tgetnum ("li");
216#ifdef TIOCGWINSZ
217    if (ioctl (0, TIOCGWINSZ, (char *) &wsize) >= 0)
218        {
219        if (wsize.ws_col != 0)
220            co = wsize.ws_col;
221        if (wsize.ws_row != 0)
222            li = wsize.ws_row;
223        }
224#endif /* TIOCGWINSZ */
225    /*
226     * Let the variables "LINES" and "COLUMNS" override the termcap
227     * entry.  Technically, this is a terminfo-ism, but I think the
228     * vast majority of users will find it pretty handy.
229     */
230    if (getenv ("COLUMNS") != NULL)
231        co = atoi (getenv ("COLUMNS"));
232    if (getenv ("LINES") != NULL)
233        li = atoi (getenv ("LINES"));
234#if MAX_SCREEN_SIZE > 0
235    if (li > MAX_SCREEN_SIZE)
236        li = MAX_SCREEN_SIZE;
237#endif /* MAX_SCREEN_SIZE > 0 */
238#if MAXCONTEXT == MINCONTEXT
239    contextsize = MINCONTEXT;
240#else /* MAXCONTEXT == MINCONTEXT */
241    if (contextsize == 0)
242#ifdef CONTEXTROUNDUP
243        contextsize = (li * CONTEXTPCT + 99) / 100;
244#else /* CONTEXTROUNDUP */
245        contextsize = (li * CONTEXTPCT) / 100;
246#endif /* CONTEXTROUNDUP */
247    if (contextsize > MAXCONTEXT)
248        contextsize = MAXCONTEXT;
249    else if (contextsize < MINCONTEXT)
250        contextsize = MINCONTEXT;
251#endif /* MAX_CONTEXT == MIN_CONTEXT */
252    /*
253     * Insist on 2 lines for the screen header, 2 for blank lines
254     * separating areas of the screen, 2 for word choices, and 2 for
255     * the minimenu, plus however many are needed for context.  If
256     * possible, make the context smaller to fit on the screen.
257     */
258    if (li < contextsize + 8  &&  contextsize > MINCONTEXT)
259        {
260        contextsize = li - 8;
261        if (contextsize < MINCONTEXT)
262            contextsize = MINCONTEXT;
263        }
264    if (li < MINCONTEXT + 8)
265        (void) fprintf (stderr, TERM_C_SMALL_SCREEN, MINCONTEXT + 8);
266
267#ifdef SIGTSTP
268#ifdef TIOCPGRP
269retry:
270#endif /* SIGTSTP */
271#endif /* TIOCPGRP */
272
273#ifdef USG
274    if (!isatty (0))
275        {
276        (void) fprintf (stderr, TERM_C_NO_BATCH);
277        exit (1);
278        }
279    (void) ioctl (0, TCGETA, (char *) &osbuf);
280    termchanged = 1;
281
282    sbuf = osbuf;
283    sbuf.c_lflag &= ~(ECHO | ECHOK | ECHONL | ICANON);
284    sbuf.c_oflag &= ~(OPOST);
285    sbuf.c_iflag &= ~(INLCR | IGNCR | ICRNL);
286    sbuf.c_cc[VMIN] = 1;
287    sbuf.c_cc[VTIME] = 1;
288    (void) ioctl (0, TCSETAW, (char *) &sbuf);
289
290    uerasechar = osbuf.c_cc[VERASE];
291    ukillchar = osbuf.c_cc[VKILL];
292
293#endif
294
295#ifdef SIGTSTP
296#ifndef USG
297    (void) sigsetmask (1<<(SIGTSTP-1) | 1<<(SIGTTIN-1) | 1<<(SIGTTOU-1));
298#endif
299#endif
300#ifdef TIOCGPGRP
301    if (ioctl (0, TIOCGPGRP, (char *) &tpgrp) != 0)
302        {
303        (void) fprintf (stderr, TERM_C_NO_BATCH);
304        exit (1);
305        }
306#endif
307#ifdef SIGTSTP
308#ifdef TIOCPGRP
309    if (tpgrp != getpgrp(0)) /* not in foreground */
310        {
311#ifndef USG
312        (void) sigsetmask (1 << (SIGTSTP - 1) | 1 << (SIGTTIN - 1));
313#endif
314        (void) signal (SIGTTOU, SIG_DFL);
315        (void) kill (0, SIGTTOU);
316        /* job stops here waiting for SIGCONT */
317        goto retry;
318        }
319#endif
320#endif
321
322#ifndef USG
323    (void) ioctl (0, TIOCGETP, (char *) &osbuf);
324#ifdef TIOCGLTC
325    (void) ioctl (0, TIOCGLTC, (char *) &oltc);
326#endif
327    termchanged = 1;
328
329    sbuf = osbuf;
330    sbuf.sg_flags &= ~ECHO;
331    sbuf.sg_flags |= TERM_MODE;
332    (void) ioctl (0, TIOCSETP, (char *) &sbuf);
333
334    uerasechar = sbuf.sg_erase;
335    ukillchar = sbuf.sg_kill;
336
337#ifdef TIOCSLTC
338    ltc = oltc;
339    ltc.t_suspc = -1;
340    (void) ioctl (0, TIOCSLTC, (char *) &ltc);
341#endif
342
343#endif /* USG */
344
345    if ((oldint = signal (SIGINT, SIG_IGN)) != SIG_IGN)
346        (void) signal (SIGINT, done);
347    if ((oldterm = signal (SIGTERM, SIG_IGN)) != SIG_IGN)
348        (void) signal (SIGTERM, done);
349
350#ifdef SIGTSTP
351#ifndef USG
352    (void) sigsetmask (0);
353#endif
354    if ((oldttin = signal (SIGTTIN, SIG_IGN)) != SIG_IGN)
355        (void) signal (SIGTTIN, onstop);
356    if ((oldttou = signal (SIGTTOU, SIG_IGN)) != SIG_IGN)
357        (void) signal (SIGTTOU, onstop);
358    if ((oldtstp = signal (SIGTSTP, SIG_IGN)) != SIG_IGN)
359        (void) signal (SIGTSTP, onstop);
360#endif
361    if (ti)
362        tputs (ti, 1, iputch);
363    }
364
365/* ARGSUSED */
366SIGNAL_TYPE done (signo)
367    int         signo;
368    {
369    if (tempfile[0] != '\0')
370        (void) unlink (tempfile);
371    if (termchanged)
372        {
373        if (te)
374            tputs (te, 1, iputch);
375#ifdef USG
376        (void) ioctl (0, TCSETAW, (char *) &osbuf);
377#else
378        (void) ioctl (0, TIOCSETP, (char *) &osbuf);
379#ifdef TIOCSLTC
380        (void) ioctl (0, TIOCSLTC, (char *) &oltc);
381#endif
382#endif
383        }
384    exit (0);
385    }
386
387#ifdef SIGTSTP
388static SIGNAL_TYPE onstop (signo)
389    int         signo;
390    {
391    if (termchanged)
392        {
393        imove (li - 1, 0);
394        if (te)
395            tputs (te, 1, iputch);
396#ifdef USG
397        (void) ioctl (0, TCSETAW, (char *) &osbuf);
398#else
399        (void) ioctl (0, TIOCSETP, (char *) &osbuf);
400#ifdef TIOCSLTC
401        (void) ioctl (0, TIOCSLTC, (char *) &oltc);
402#endif
403#endif
404        }
405    (void) fflush (stdout);
406    (void) signal (signo, SIG_DFL);
407#ifndef USG
408    (void) sigsetmask (sigblock (0) & ~(1 << (signo - 1)));
409#endif
410    (void) kill (0, SIGSTOP);
411    /* stop here until continued */
412    (void) signal (signo, onstop);
413    if (termchanged)
414        {
415#ifdef USG
416        (void) ioctl (0, TCSETAW, (char *) &sbuf);
417#else
418        (void) ioctl (0, TIOCSETP, (char *) &sbuf);
419#ifdef TIOCSLTC
420        (void) ioctl (0, TIOCSLTC, (char *) &ltc);
421#endif
422#endif
423        if (ti)
424            tputs (ti, 1, iputch);
425        }
426    }
427#endif
428
429#ifndef USESH
430#define NEED_SHELLESCAPE
431#endif /* USESH */
432#ifndef REGEX_LOOKUP
433#define NEED_SHELLESCAPE
434#endif /* REGEX_LOOKUP */
435
436void stop ()
437    {
438#ifdef SIGTSTP
439    onstop (SIGTSTP);
440#else
441    /* for System V and MSDOS */
442    imove (li - 1, 0);
443    (void) fflush (stdout);
444#ifdef NEED_SHELLESCAPE
445    if (getenv ("SHELL"))
446        (void) shellescape (getenv ("SHELL"));
447    else
448        (void) shellescape ("sh");
449#else
450    shescape ("");
451#endif /* NEED_SHELLESCAPE */
452#endif /* SIGTSTP */
453    }
454
455/* Fork and exec a process.  Returns NZ if command found, regardless of
456** command's return status.  Returns zero if command was not found.
457** Doesn't use a shell.
458*/
459#ifdef NEED_SHELLESCAPE
460int shellescape (buf)
461    char *      buf;
462    {
463    char *      argv[100];
464    char *      cp = buf;
465    int         i = 0;
466    int         termstat;
467
468    /* parse buf to args (destroying it in the process) */
469    while (*cp != '\0')
470        {
471        while (*cp == ' '  ||  *cp == '\t')
472            ++cp;
473        if (*cp == '\0')
474            break;
475        argv[i++] = cp;
476        while (*cp != ' '  &&  *cp != '\t'  &&  *cp != '\0')
477            ++cp;
478        if (*cp != '\0')
479            *cp++ = '\0';
480        }
481    argv[i] = NULL;
482
483#ifdef USG
484    (void) ioctl (0, TCSETAW, (char *) &osbuf);
485#else
486    (void) ioctl (0, TIOCSETP, (char *) &osbuf);
487#ifdef TIOCSLTC
488    (void) ioctl (0, TIOCSLTC, (char *) &oltc);
489#endif /* TIOCSLTC */
490#endif
491    (void) signal (SIGINT, oldint);
492    (void) signal (SIGTERM, oldterm);
493#ifdef SIGTSTP
494    (void) signal (SIGTTIN, oldttin);
495    (void) signal (SIGTTOU, oldttou);
496    (void) signal (SIGTSTP, oldtstp);
497#endif
498    if ((i = fork ()) == 0)
499        {
500        (void) execvp (argv[0], (char **) argv);
501        _exit (123);            /* Command not found */
502        }
503    else if (i > 0)
504        {
505        while (wait (&termstat) != i)
506            ;
507        termstat = (termstat == (123 << 8)) ? 0 : -1;
508        }
509    else
510        {
511        (void) printf (TERM_C_CANT_FORK, MAYBE_CR (stderr));
512        termstat = -1;          /* Couldn't fork */
513        }
514
515    if (oldint != SIG_IGN)
516        (void) signal (SIGINT, done);
517    if (oldterm != SIG_IGN)
518        (void) signal (SIGTERM, done);
519
520#ifdef SIGTSTP
521    if (oldttin != SIG_IGN)
522        (void) signal (SIGTTIN, onstop);
523    if (oldttou != SIG_IGN)
524        (void) signal (SIGTTOU, onstop);
525    if (oldtstp != SIG_IGN)
526        (void) signal (SIGTSTP, onstop);
527#endif
528
529#ifdef USG
530    (void) ioctl (0, TCSETAW, (char *) &sbuf);
531#else
532    (void) ioctl (0, TIOCSETP, (char *) &sbuf);
533#ifdef TIOCSLTC
534    (void) ioctl (0, TIOCSLTC, (char *) &ltc);
535#endif /* TIOCSLTC */
536#endif
537    if (termstat)
538        {
539        (void) printf (TERM_C_TYPE_SPACE);
540        (void) fflush (stdout);
541#ifdef COMMANDFORSPACE
542        i = GETKEYSTROKE ();
543        if (i != ' ' && i != '\n' && i != '\r')
544            (void) ungetc (i, stdin);
545#else
546        while (GETKEYSTROKE () != ' ')
547            ;
548#endif
549        }
550    return (termstat);
551    }
552#endif /* NEED_SHELLESCAPE */
553
554#ifdef  USESH
555void shescape (buf)
556    char *      buf;
557    {
558#ifdef COMMANDFORSPACE
559    int         ch;
560#endif
561#ifdef __DJGPP__
562    char        curdir[MAXPATHLEN];
563#endif
564
565#ifdef USG
566    (void) ioctl (0, TCSETAW, (char *) &osbuf);
567#else
568    (void) ioctl (0, TIOCSETP, (char *) &osbuf);
569#ifdef TIOCSLTC
570    (void) ioctl (0, TIOCSLTC, (char *) &oltc);
571#endif
572#endif
573#ifdef __DJGPP__
574    /* Don't erase the screen if they want to run a single command,
575     * otherwise they will be unable to see its output.
576     */
577    if (buf[0] == '\0')
578        djgpp_restore_screen ();
579    /* Change and restore the current directory, because it's a global
580     * notion on MS-DOS/MS-Windows.
581     */
582    getcwd (curdir, MAXPATHLEN);
583#endif
584    (void) signal (SIGINT, oldint);
585    (void) signal (SIGTERM, oldterm);
586#ifdef SIGTSTP
587    (void) signal (SIGTTIN, oldttin);
588    (void) signal (SIGTTOU, oldttou);
589    (void) signal (SIGTSTP, oldtstp);
590#endif
591
592    (void) system (buf);
593
594    if (oldint != SIG_IGN)
595        (void) signal (SIGINT, done);
596    if (oldterm != SIG_IGN)
597        (void) signal (SIGTERM, done);
598
599#ifdef SIGTSTP
600    if (oldttin != SIG_IGN)
601        (void) signal (SIGTTIN, onstop);
602    if (oldttou != SIG_IGN)
603        (void) signal (SIGTTOU, onstop);
604    if (oldtstp != SIG_IGN)
605        (void) signal (SIGTSTP, onstop);
606#endif
607#ifdef __DJGPP__
608    if (buf[0] == '\0')
609        djgpp_ispell_screen ();
610    chdir (curdir);
611#endif
612
613#ifdef USG
614    (void) ioctl (0, TCSETAW, (char *) &sbuf);
615#else
616    (void) ioctl (0, TIOCSETP, (char *) &sbuf);
617#ifdef TIOCSLTC
618    (void) ioctl (0, TIOCSLTC, (char *) &ltc);
619#endif
620#endif
621    (void) printf (TERM_C_TYPE_SPACE);
622    (void) fflush (stdout);
623#ifdef COMMANDFORSPACE
624    ch = GETKEYSTROKE ();
625    if (ch != ' '  &&  ch != '\n'  &&  ch != '\r')
626        (void) ungetc (ch, stdin);
627#else
628    while (GETKEYSTROKE () != ' ')
629        ;
630#endif
631    }
632#endif
Note: See TracBrowser for help on using the repository browser.