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 /*
34 * terminal input functions
35 *
36 * cscope - interactive C symbol cross-reference
37 */
38
39 #include "global-cscope.h"
40 #if defined(USE_NCURSES) && !defined(RENAMED_NCURSES)
41 #include <ncurses.h>
42 #else
43 #include <curses.h>
44 #endif
45 #include <setjmp.h> /* jmp_buf */
46 #include <stdlib.h>
47 #include <errno.h>
48 #if HAVE_SYS_TERMIOS_H
49 #include <sys/termios.h>
50 #endif
51 #if defined(_WIN32) && !defined(__CYGWIN__)
52 #define WIN32_LEAN_AND_MEAN
53 #define __OBJC__ /* work around BOOL redefinition */
54 #include <windows.h>
55 #endif
56
57 static jmp_buf env; /**< setjmp/longjmp buffer */
58 static int prevchar; /**< previous, ungotten character */
59
60 /* Internal prototypes: */
61 static RETSIGTYPE catchint(int sig);
62
63 /** catch the interrupt signal */
64
65 /*ARGSUSED*/
66 static RETSIGTYPE
catchint(int sig)67 catchint(int sig)
68 {
69 (void) sig; /* 'use' it, to avoid a warning */
70
71 signal(SIGINT, catchint);
72 longjmp(env, 1);
73 }
74
75 /** unget a character */
76 void
myungetch(int c)77 myungetch(int c)
78 {
79 prevchar = c;
80 }
81
82 /** get a character from the terminal */
83 int
mygetch(void)84 mygetch(void)
85 {
86 #if !defined(_WIN32) || !defined(__CYGWIN__)
87 /* longjmp won't work, it's in a different thread */
88 sighandler_t savesig; /* old value of signal */
89 #endif
90 int c;
91
92 /* change an interrupt signal to a break key character */
93 if (setjmp(env) == 0) {
94 #if defined(_WIN32) && !defined(__CYGWIN__)
95 /* turn off Ctrl+C handling (PDCurses does this, but it gets turned on
96 again by CMD during system) */
97 SetConsoleMode( GetStdHandle( STD_INPUT_HANDLE ), 0 );
98 #else
99 savesig = signal(SIGINT, catchint);
100 #endif
101 refresh(); /* update the display */
102 mousereinit(); /* curses can change the menu number */
103 if(prevchar) {
104 c = prevchar;
105 prevchar = 0;
106 } else {
107 c = -1;
108 while (c == -1) {
109 /* get a character from the terminal */
110 c = getch();
111 if ((c == -1) && (errno != EINTR))
112 break;
113 }
114 }
115 } else { /* longjmp to here from signal handler */
116 c = KEY_BREAK;
117 }
118 #if !defined(_WIN32) || !defined(__CYGWIN__)
119 signal(SIGINT, savesig);
120 #endif
121 return(c);
122 }
123
124
125 /** get a line from the terminal in non-canonical mode */
126 int
mygetline(char p[],char s[],unsigned size,int firstchar,BOOL iscaseless)127 mygetline(char p[], char s[], unsigned size, int firstchar, BOOL iscaseless)
128 {
129 int c;
130 unsigned int i = 0, j;
131 char *sright; /* substring to the right of the cursor */
132 unsigned int ri = 0; /* position in right-string */
133
134 /* Inserts and deletes are always performed on the left-string,
135 * but we'll also have a right-string 'sright' to hold characters
136 * which are on the right of the cursor [insertion point].
137 *
138 * Think of 'sright' as a stack -- we push chars into it when the cursor
139 * moves left, and we pop chars off it when the cursor moves right again.
140 * At the end of the function, we'll pop off any remaining characters
141 * onto the end of 's'
142 */
143 sright = calloc(sizeof(char), size );
144
145 strcpy ( s, p);
146 i += strlen(p);
147 /* if a character already has been typed */
148 if (firstchar != '\0') {
149 if(iscaseless == YES) {
150 firstchar = tolower(firstchar);
151 }
152 addch(firstchar); /* display it */
153 s[i++] = firstchar; /* save it */
154 }
155 /* until the end of the line is reached */
156 while ((c = mygetch()) != '\r' && c != '\n' && c != KEY_ENTER) {
157 if (c == KEY_LEFT || c == ctrl('B')) { /* left */
158 if (i > 0) {
159 addch('\b');
160 /* move this char into the second (rhs) string */
161 sright[ri++] = s[--i];
162 }
163 } else if (c == KEY_RIGHT || c == ctrl('F')) { /* right */
164 if (i < size && ri > 0) {
165 /* move this char to the left of the cursor */
166 s[i++] = sright[--ri];
167 addch(s[i-1]);
168 }
169 } else if (
170 #ifdef KEY_HOME
171 c == KEY_HOME ||
172 #endif
173 c == ctrl('A') ) {
174 while (i > 0) {
175 sright[ri++] = s[--i];
176 addch('\b');
177 addch(s[i]);
178 addch('\b');
179 }
180 } else if (
181 #ifdef KEY_END
182 c == KEY_END ||
183 #endif
184 c == ctrl('E') ) {
185 while (ri > 0) {
186 s[i++] = sright[--ri];
187 addch(s[i-1]);
188 }
189 } else if (c == erasechar() || c == KEY_BACKSPACE
190 || c == DEL || c == ctrl('H') ) {
191 /* erase */
192 if (i > 0) {
193 if (ri == 0) {
194 addstr("\b \b");
195 } else {
196 addch('\b');
197 delch();
198 }
199 s[i] = '\0';
200 --i;
201 }
202 } else if (c == killchar() || c == KEY_BREAK) {
203 /* kill */
204 for (j = 0; j < i; ++j) {
205 addch('\b');
206 }
207 for (j = 0; j < i; ++j) {
208 addch(' ');
209 }
210 for (j = 0; j < i; ++j) {
211 addch('\b');
212 }
213 i = 0;
214 } else if (isprint(c) || c == '\t') {
215 /* printable */
216 if(iscaseless == YES) {
217 c = tolower(c);
218 }
219 /* if it will fit on the line */
220 if (i < size) {
221 s[i++] = c; /* save it */
222 if (ri == 0) {
223 addch(c); /* display it */
224 } else {
225 insch(c); /* display it */
226 addch(c); /* advance cursor */
227 }
228 }
229 #if UNIXPC
230 } else if (unixpcmouse == YES && c == ESC) { /* mouse */
231 getmouseaction(ESC); /* ignore it */
232 #endif
233 } else if (mouse == YES && c == ctrl('X')) {
234 getmouseaction(ctrl('X')); /* ignore it */
235 } else if (c == EOF) { /* end-of-file */
236 break;
237 }
238
239 /* return on an empty line to allow a command to be entered */
240 if (firstchar != '\0' && (i+ri) == 0) {
241 break;
242 }
243 }
244
245 /* move any remaining chars on the rhs of the cursor
246 * onto the end of our string
247 */
248 while (ri > 0) {
249 s[i++] = sright[--ri];
250 }
251 free(sright);
252
253 s[i] = '\0';
254 return(i);
255 }
256
257 /** ask user to enter a character after reading the message */
258
259 void
askforchar(void)260 askforchar(void)
261 {
262 addstr("Type any character to continue: ");
263 mygetch();
264 }
265
266 /** ask user to press the RETURN key after reading the message */
267
268 void
askforreturn(void)269 askforreturn(void)
270 {
271 fprintf(stderr, "Press the RETURN key to continue: ");
272 getchar();
273 /* HBB 20060419: message probably messed up the screen --- redraw */
274 if (incurses == YES) {
275 redrawwin(curscr);
276 }
277 }
278
279 /** expand the ~ and $ shell meta characters in a path */
280
281 void
shellpath(char * out,int limit,char * in)282 shellpath(char *out, int limit, char *in)
283 {
284 char *lastchar;
285 char *s, *v;
286
287 /* skip leading white space */
288 while (isspace((unsigned char)*in)) {
289 ++in;
290 }
291 lastchar = out + limit - 1;
292
293 /* a tilde (~) by itself represents $HOME; followed by a name it
294 represents the $LOGDIR of that login name */
295 if (*in == '~') {
296 *out++ = *in++; /* copy the ~ because it may not be expanded */
297
298 /* get the login name */
299 s = out;
300 while (s < lastchar && *in != '/' && *in != '\0' && !isspace((unsigned char)*in)) {
301 *s++ = *in++;
302 }
303 *s = '\0';
304
305 /* if the login name is null, then use $HOME */
306 if (*out == '\0') {
307 v = getenv("HOME");
308 } else { /* get the home directory of the login name */
309 v = logdir(out);
310 }
311 /* copy the directory name if it isn't too big */
312 if (v != NULL && strlen(v) < (lastchar - out)) {
313 strcpy(out - 1, v);
314 out += strlen(v) - 1;
315 } else {
316 /* login not found, so ~ must be part of the file name */
317 out += strlen(out);
318 }
319 }
320 /* get the rest of the path */
321 while (out < lastchar && *in != '\0' && !isspace((unsigned char)*in)) {
322
323 /* look for an environment variable */
324 if (*in == '$') {
325 *out++ = *in++; /* copy the $ because it may not be expanded */
326
327 /* get the variable name */
328 s = out;
329 while (s < lastchar && *in != '/' && *in != '\0' &&
330 !isspace((unsigned char)*in)) {
331 *s++ = *in++;
332 }
333 *s = '\0';
334
335 /* get its value, but only it isn't too big */
336 if ((v = getenv(out)) != NULL && strlen(v) < (lastchar - out)) {
337 strcpy(out - 1, v);
338 out += strlen(v) - 1;
339 } else {
340 /* var not found, or too big, so assume $ must be part of the
341 * file name */
342 out += strlen(out);
343 }
344 }
345 else { /* ordinary character */
346 *out++ = *in++;
347 }
348 }
349 *out = '\0';
350 }
351