1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright 2015 Gary Mills
  24  * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
  25  */
  26 
  27 /*      Copyright (c) 1988 AT&T     */
  28 /*        All Rights Reserved   */
  29 
  30 /*
  31  *      cscope - interactive C symbol cross-reference
  32  *
  33  *      terminal input functions
  34  */
  35 
  36 #include "global.h"
  37 #include <curses.h>       /* KEY_BACKSPACE, KEY_BREAK, and KEY_ENTER */
  38 #include <setjmp.h>       /* jmp_buf */
  39 
  40 static  jmp_buf env;            /* setjmp/longjmp buffer */
  41 static  int     prevchar;       /* previous, ungotten character */
  42 
  43 /* catch the interrupt signal */
  44 
  45 /*ARGSUSED*/
  46 SIGTYPE
  47 catchint(int sig)
  48 {
  49         (void) signal(SIGINT, catchint);
  50         longjmp(env, 1);
  51 }
  52 
  53 /* unget a character */
  54 
  55 int
  56 ungetch(int c)
  57 {
  58         prevchar = c;
  59         return (0);
  60 }
  61 
  62 /* get a character from the terminal */
  63 
  64 int
  65 mygetch(void)
  66 {
  67         SIGTYPE (*volatile savesig)() = SIG_DFL; /* old value of signal */
  68         int     c;
  69 
  70         /* change an interrupt signal to a break key character */
  71         if (setjmp(env) == 0) {
  72                 savesig = signal(SIGINT, catchint);
  73                 (void) refresh();       /* update the display */
  74                 reinitmouse();  /* curses can change the menu number */
  75                 if (prevchar) {
  76                         c = prevchar;
  77                         prevchar = 0;
  78                 } else {
  79                         c = getch();    /* get a character from the terminal */
  80                 }
  81         } else {        /* longjmp to here from signal handler */
  82                 c = KEY_BREAK;
  83         }
  84         (void) signal(SIGINT, savesig);
  85         return (c);
  86 }
  87 
  88 /* get a line from the terminal in non-canonical mode */
  89 
  90 int
  91 getaline(char s[], size_t size, int firstchar, BOOL iscaseless)
  92 {
  93         int     c, i = 0;
  94         int     j;
  95 
  96         /* if a character already has been typed */
  97         if (firstchar != '\0') {
  98                 if (iscaseless == YES) {
  99                         firstchar = tolower(firstchar);
 100                 }
 101                 (void) addch((unsigned)firstchar);      /* display it */
 102                 s[i++] = firstchar;     /* save it */
 103         }
 104         /* until the end of the line is reached */
 105         while ((c = mygetch()) != '\r' && c != '\n' && c != KEY_ENTER &&
 106             c != '\003' && c != KEY_BREAK) {
 107                 if (c == erasechar() || c == '\b' ||            /* erase */
 108                     c == KEY_BACKSPACE) {
 109                         if (i > 0) {
 110                                 (void) addstr("\b \b");
 111                                 --i;
 112                         }
 113                 } else if (c == killchar()) {                   /* kill */
 114                         for (j = 0; j < i; ++j) {
 115                                 (void) addch('\b');
 116                         }
 117                         for (j = 0; j < i; ++j) {
 118                                 (void) addch(' ');
 119                         }
 120                         for (j = 0; j < i; ++j) {
 121                                 (void) addch('\b');
 122                         }
 123                         i = 0;
 124                 } else if (isprint(c) || c == '\t') {           /* printable */
 125                         if (iscaseless == YES) {
 126                                 c = tolower(c);
 127                         }
 128                         /* if it will fit on the line */
 129                         if (i < size) {
 130                                 (void) addch((unsigned)c);      /* display it */
 131                                 s[i++] = c;             /* save it */
 132                         }
 133                 } else if (c == ctrl('X')) {
 134                         /* mouse */
 135                         (void) getmouseevent();         /* ignore it */
 136                 } else if (c == EOF) {                  /* end-of-file */
 137                         break;
 138                 }
 139                 /* return on an empty line to allow a command to be entered */
 140                 if (firstchar != '\0' && i == 0) {
 141                         break;
 142                 }
 143         }
 144         s[i] = '\0';
 145         return (i);
 146 }
 147 
 148 /* ask user to enter a character after reading the message */
 149 
 150 void
 151 askforchar(void)
 152 {
 153         (void) addstr("Type any character to continue: ");
 154         (void) mygetch();
 155 }
 156 
 157 /* ask user to press the RETURN key after reading the message */
 158 
 159 void
 160 askforreturn(void)
 161 {
 162         if (linemode == NO) {
 163                 (void) fprintf(stderr, "Press the RETURN key to continue: ");
 164                 (void) getchar();
 165         }
 166 }
 167 
 168 /* expand the ~ and $ shell meta characters in a path */
 169 
 170 void
 171 shellpath(char *out, int limit, char *in)
 172 {
 173         char    *lastchar;
 174         char    *s, *v;
 175 
 176         /* skip leading white space */
 177         while (isspace(*in)) {
 178                 ++in;
 179         }
 180         lastchar = out + limit - 1;
 181 
 182         /*
 183          * a tilde (~) by itself represents $HOME; followed by a name it
 184          * represents the $LOGDIR of that login name
 185          */
 186         if (*in == '~') {
 187                 *out++ = *in++; /* copy the ~ because it may not be expanded */
 188 
 189                 /* get the login name */
 190                 s = out;
 191                 while (s < lastchar && *in != '/' && *in != '\0' &&
 192                     !isspace(*in)) {
 193                         *s++ = *in++;
 194                 }
 195                 *s = '\0';
 196 
 197                 /* if the login name is null, then use $HOME */
 198                 if (*out == '\0') {
 199                         v = getenv("HOME");
 200                 } else {        /* get the home directory of the login name */
 201                         v = logdir(out);
 202                 }
 203                 /* copy the directory name */
 204                 if (v != NULL) {
 205                         (void) strcpy(out - 1, v);
 206                         out += strlen(v) - 1;
 207                 } else {
 208                         /* login not found so ~ must be part of the file name */
 209                         out += strlen(out);
 210                 }
 211         }
 212         /* get the rest of the path */
 213         while (out < lastchar && *in != '\0' && !isspace(*in)) {
 214 
 215                 /* look for an environment variable */
 216                 if (*in == '$') {
 217                         /* copy the $ because it may not be expanded */
 218                         *out++ = *in++;
 219 
 220                         /* get the variable name */
 221                         s = out;
 222                         while (s < lastchar && *in != '/' && *in != '\0' &&
 223                             !isspace(*in)) {
 224                                 *s++ = *in++;
 225                         }
 226                         *s = '\0';
 227 
 228                         /* get its value */
 229                         if ((v = getenv(out)) != NULL) {
 230                                 (void) strcpy(out - 1, v);
 231                                 out += strlen(v) - 1;
 232                         } else {
 233                                 /*
 234                                  * var not found, so $ must be part of
 235                                  * the file name
 236                                  */
 237                                 out += strlen(out);
 238                         }
 239                 } else {        /* ordinary character */
 240                         *out++ = *in++;
 241                 }
 242         }
 243         *out = '\0';
 244 }