Imported Upstream version 15.8a
[platform/upstream/cscope.git] / src / input.c
1 /*===========================================================================
2  Copyright (c) 1998-2000, The Santa Cruz Operation 
3  All rights reserved.
4  
5  Redistribution and use in source and binary forms, with or without
6  modification, are permitted provided that the following conditions are met:
7
8  *Redistributions of source code must retain the above copyright notice,
9  this list of conditions and the following disclaimer.
10
11  *Redistributions in binary form must reproduce the above copyright notice,
12  this list of conditions and the following disclaimer in the documentation
13  and/or other materials provided with the distribution.
14
15  *Neither name of The Santa Cruz Operation nor the names of its contributors
16  may be used to endorse or promote products derived from this software
17  without specific prior written permission. 
18
19  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
20  IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
23  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  INTERRUPTION)
27  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
30  DAMAGE. 
31  =========================================================================*/
32
33 /*      cscope - interactive C symbol cross-reference
34  *
35  *      terminal input functions
36  */
37
38 #include "global.h"
39 #if defined(USE_NCURSES) && !defined(RENAMED_NCURSES)
40 #include <ncurses.h>
41 #else
42 #include <curses.h>
43 #endif
44 #include <setjmp.h>     /* jmp_buf */
45 #include <stdlib.h>
46 #include <errno.h>
47 #if HAVE_SYS_TERMIOS_H
48 #include <sys/termios.h>
49 #endif
50
51 static char const rcsid[] = "$Id: input.c,v 1.15 2006/08/20 15:00:34 broeker Exp $";
52
53 static  jmp_buf env;            /* setjmp/longjmp buffer */
54 static  int     prevchar;       /* previous, ungotten character */
55
56 /* Internal prototypes: */
57 static RETSIGTYPE catchint(int sig);
58
59 /* catch the interrupt signal */
60
61 /*ARGSUSED*/
62 static RETSIGTYPE
63 catchint(int sig)
64 {
65         (void) sig;             /* 'use' it, to avoid a warning */
66
67         signal(SIGINT, catchint);
68         longjmp(env, 1);
69 }
70
71 /* unget a character */
72 void
73 myungetch(int c)
74 {
75         prevchar = c;
76 }
77
78 /* get a character from the terminal */
79 int
80 mygetch(void)
81 {
82     sighandler_t savesig; /* old value of signal */
83     int c;
84
85     /* change an interrupt signal to a break key character */
86     if (setjmp(env) == 0) {
87         savesig = signal(SIGINT, catchint);
88         refresh();      /* update the display */
89         mousereinit();  /* curses can change the menu number */
90         if(prevchar) {
91             c = prevchar;
92             prevchar = 0;
93         } else {
94             c = -1;
95             while (c == -1) {
96                 /* get a character from the terminal */
97                 c = getch();
98                 if ((c == -1) && (errno != EINTR))
99                     break;
100             }
101         }
102     } else {    /* longjmp to here from signal handler */
103         c = KEY_BREAK;
104     }
105     signal(SIGINT, savesig);
106     return(c);
107 }
108
109
110 /* get a line from the terminal in non-canonical mode */
111 int
112 mygetline(char p[], char s[], unsigned size, int firstchar, BOOL iscaseless)
113 {
114     int c;
115     unsigned int i = 0, j;
116     char *sright;       /* substring to the right of the cursor */
117     unsigned int ri = 0;                /* position in right-string */
118
119     /* Inserts and deletes are always performed on the left-string,
120      * but we'll also have a right-string 'sright' to hold characters
121      * which are on the right of the cursor [insertion point].
122      *
123      * Think of 'sright' as a stack -- we push chars into it when the cursor
124      * moves left, and we pop chars off it when the cursor moves right again.
125      * At the end of the function, we'll pop off any remaining characters
126      * onto the end of 's'
127      */
128     sright = calloc(sizeof(char), size );
129
130     strcpy ( s, p);
131     i += strlen(p);
132     /* if a character already has been typed */
133     if (firstchar != '\0') {
134         if(iscaseless == YES) {
135             firstchar = tolower(firstchar);
136         }
137         addch(firstchar);       /* display it */
138         s[i++] = firstchar;     /* save it */
139     }
140     /* until the end of the line is reached */
141     while ((c = mygetch()) != '\r' && c != '\n' && c != KEY_ENTER) {
142         if (c == KEY_LEFT || c == ctrl('B')) {  /* left */
143             if (i > 0) {
144                 addch('\b');
145                 /* move this char into the second (rhs) string */
146                 sright[ri++] = s[--i];
147             }
148         } else if (c == KEY_RIGHT || c == ctrl('F')) {  /* right */
149             if (i < size && ri > 0) {
150                 /* move this char to the left of the cursor */
151                 s[i++] = sright[--ri];
152                 addch(s[i-1]);
153             }
154         } else if (
155 #ifdef KEY_HOME
156                    c == KEY_HOME ||
157 #endif
158                    c == ctrl('A') ) {
159             while (i > 0) {
160                 sright[ri++] = s[--i];
161                 addch('\b');
162                 addch(s[i]);
163                 addch('\b');
164             }
165         } else if (
166 #ifdef KEY_END
167                    c == KEY_END ||
168 #endif
169                    c == ctrl('E') ) {
170             while (ri > 0) {
171                 s[i++] = sright[--ri];
172                 addch(s[i-1]);
173             }
174         } else if (c == erasechar() || c == KEY_BACKSPACE
175                    || c == DEL || c == ctrl('H') ) {
176             /* erase */
177             if (i > 0) {
178                 if (ri == 0)  {
179                     addstr("\b \b");
180                 } else {
181                     addch('\b');
182                     delch();
183                 }
184                 s[i] = '\0';
185                 --i;
186             }
187         } else if (c == killchar() || c == KEY_BREAK) {
188             /* kill */
189             for (j = 0; j < i; ++j) {
190                 addch('\b');
191             }
192             for (j = 0; j < i; ++j) {
193                 addch(' ');
194             }
195             for (j = 0; j < i; ++j) {
196                 addch('\b');
197             }
198             i = 0;
199         } else if (isprint(c) || c == '\t') {
200             /* printable */
201             if(iscaseless == YES) {
202                 c = tolower(c);
203             }
204             /* if it will fit on the line */
205             if (i < size) {
206                 s[i++] = c;     /* save it */
207                 if (ri == 0) {
208                     addch(c);   /* display it */
209                 } else {
210                     insch(c);   /* display it */
211                     addch(c);   /* advance cursor */
212                 }
213             }
214 #if UNIXPC
215         } else if (unixpcmouse == YES && c == ESC) {    /* mouse */
216             getmouseaction(ESC);        /* ignore it */
217 #endif
218         } else if (mouse == YES && c == ctrl('X')) {
219             getmouseaction(ctrl('X'));  /* ignore it */
220         } else if (c == EOF) {                          /* end-of-file */
221             break;
222         }
223
224         /* return on an empty line to allow a command to be entered */
225         if (firstchar != '\0' && (i+ri) == 0) {
226             break;
227         }
228     }
229
230     /* move any remaining chars on the rhs of the cursor
231      * onto the end of our string
232      */
233     while (ri > 0) {
234         s[i++] = sright[--ri];
235     }
236     free(sright);
237
238     s[i] = '\0';
239     return(i);
240 }
241
242 /* ask user to enter a character after reading the message */
243
244 void
245 askforchar(void)
246 {
247     addstr("Type any character to continue: ");
248     mygetch();
249 }
250
251 /* ask user to press the RETURN key after reading the message */
252
253 void
254 askforreturn(void)
255 {
256     fprintf(stderr, "Press the RETURN key to continue: ");
257     getchar();
258     /* HBB 20060419: message probably messed up the screen --- redraw */
259     if (incurses == YES) {
260         redrawwin(curscr);
261     }
262 }
263
264 /* expand the ~ and $ shell meta characters in a path */
265
266 void
267 shellpath(char *out, int limit, char *in) 
268 {
269     char        *lastchar;
270     char        *s, *v;
271
272     /* skip leading white space */
273     while (isspace((unsigned char)*in)) {
274         ++in;
275     }
276     lastchar = out + limit - 1;
277
278     /* a tilde (~) by itself represents $HOME; followed by a name it
279        represents the $LOGDIR of that login name */
280     if (*in == '~') {
281         *out++ = *in++; /* copy the ~ because it may not be expanded */
282
283         /* get the login name */
284         s = out;
285         while (s < lastchar && *in != '/' && *in != '\0' && !isspace((unsigned char)*in)) {
286             *s++ = *in++;
287         }
288         *s = '\0';
289
290         /* if the login name is null, then use $HOME */
291         if (*out == '\0') {
292             v = getenv("HOME");
293         } else {        /* get the home directory of the login name */
294             v = logdir(out);
295         }
296         /* copy the directory name if it isn't too big */
297         if (v != NULL && strlen(v) < (lastchar - out)) {
298             strcpy(out - 1, v);
299             out += strlen(v) - 1;
300         } else {
301             /* login not found, so ~ must be part of the file name */
302             out += strlen(out);
303         }
304     }
305     /* get the rest of the path */
306     while (out < lastchar && *in != '\0' && !isspace((unsigned char)*in)) {
307
308         /* look for an environment variable */
309         if (*in == '$') {
310             *out++ = *in++;     /* copy the $ because it may not be expanded */
311
312             /* get the variable name */
313             s = out;
314             while (s < lastchar && *in != '/' && *in != '\0' &&
315                    !isspace((unsigned char)*in)) {
316                 *s++ = *in++;
317             }
318             *s = '\0';
319         
320             /* get its value, but only it isn't too big */
321             if ((v = getenv(out)) != NULL && strlen(v) < (lastchar - out)) {
322                 strcpy(out - 1, v);
323                 out += strlen(v) - 1;
324             } else {
325                 /* var not found, or too big, so assume $ must be part of the
326                  * file name */
327                 out += strlen(out);
328             }
329         }
330         else {  /* ordinary character */
331             *out++ = *in++;
332         }
333     }
334     *out = '\0';
335 }