root/maint/gnulib/lib/isatty.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. initialize
  2. IsConsoleHandle
  3. IsCygwinConsoleHandle
  4. _isatty_nothrow
  5. isatty

   1 /* isatty() replacement.
   2    Copyright (C) 2012-2021 Free Software Foundation, Inc.
   3 
   4    This file is free software: you can redistribute it and/or modify
   5    it under the terms of the GNU Lesser General Public License as
   6    published by the Free Software Foundation; either version 2.1 of the
   7    License, or (at your option) any later version.
   8 
   9    This file is distributed in the hope that it will be useful,
  10    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12    GNU Lesser General Public License for more details.
  13 
  14    You should have received a copy of the GNU Lesser General Public License
  15    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
  16 
  17 #include <config.h>
  18 
  19 /* Specification.  */
  20 #include <unistd.h>
  21 
  22 /* This replacement is enabled on native Windows.  */
  23 
  24 #include <errno.h>
  25 #include <string.h>
  26 
  27 /* Get declarations of the Win32 API functions.  */
  28 #define WIN32_LEAN_AND_MEAN
  29 #include <windows.h>
  30 
  31 #if HAVE_MSVC_INVALID_PARAMETER_HANDLER
  32 # include "msvc-inval.h"
  33 #endif
  34 
  35 /* Get _get_osfhandle().  */
  36 #if GNULIB_MSVC_NOTHROW
  37 # include "msvc-nothrow.h"
  38 #else
  39 # include <io.h>
  40 #endif
  41 
  42 /* Don't assume that UNICODE is not defined.  */
  43 #undef LoadLibrary
  44 #define LoadLibrary LoadLibraryA
  45 #undef QueryFullProcessImageName
  46 #define QueryFullProcessImageName QueryFullProcessImageNameA
  47 
  48 #if !(_WIN32_WINNT >= _WIN32_WINNT_VISTA)
  49 
  50 /* Avoid warnings from gcc -Wcast-function-type.  */
  51 # define GetProcAddress \
  52    (void *) GetProcAddress
  53 
  54 /* GetNamedPipeClientProcessId was introduced only in Windows Vista.  */
  55 typedef BOOL (WINAPI * GetNamedPipeClientProcessIdFuncType) (HANDLE hPipe,
  56                                                              PULONG pClientProcessId);
  57 static GetNamedPipeClientProcessIdFuncType GetNamedPipeClientProcessIdFunc = NULL;
  58 /* QueryFullProcessImageName was introduced only in Windows Vista.  */
  59 typedef BOOL (WINAPI * QueryFullProcessImageNameFuncType) (HANDLE hProcess,
  60                                                            DWORD dwFlags,
  61                                                            LPSTR lpExeName,
  62                                                            PDWORD pdwSize);
  63 static QueryFullProcessImageNameFuncType QueryFullProcessImageNameFunc = NULL;
  64 static BOOL initialized = FALSE;
  65 
  66 static void
  67 initialize (void)
     /* [previous][next][first][last][top][bottom][index][help] */
  68 {
  69   HMODULE kernel32 = LoadLibrary ("kernel32.dll");
  70   if (kernel32 != NULL)
  71     {
  72       GetNamedPipeClientProcessIdFunc =
  73         (GetNamedPipeClientProcessIdFuncType) GetProcAddress (kernel32, "GetNamedPipeClientProcessId");
  74       QueryFullProcessImageNameFunc =
  75         (QueryFullProcessImageNameFuncType) GetProcAddress (kernel32, "QueryFullProcessImageNameA");
  76     }
  77   initialized = TRUE;
  78 }
  79 
  80 #else
  81 
  82 # define GetNamedPipeClientProcessIdFunc GetNamedPipeClientProcessId
  83 # define QueryFullProcessImageNameFunc QueryFullProcessImageName
  84 
  85 #endif
  86 
  87 static BOOL IsConsoleHandle (HANDLE h)
     /* [previous][next][first][last][top][bottom][index][help] */
  88 {
  89   DWORD mode;
  90   /* GetConsoleMode
  91      <https://docs.microsoft.com/en-us/windows/console/getconsolemode> */
  92   return GetConsoleMode (h, &mode) != 0;
  93 }
  94 
  95 static BOOL IsCygwinConsoleHandle (HANDLE h)
     /* [previous][next][first][last][top][bottom][index][help] */
  96 {
  97   /* A handle to a Cygwin console is in fact a named pipe whose client process
  98      and server process is <CYGWIN_INSTALL_DIR>\bin\mintty.exe.  */
  99   BOOL result = FALSE;
 100   ULONG processId;
 101 
 102 #if !(_WIN32_WINNT >= _WIN32_WINNT_VISTA)
 103   if (!initialized)
 104     initialize ();
 105 #endif
 106 
 107   /* GetNamedPipeClientProcessId
 108      <https://docs.microsoft.com/en-us/windows/desktop/api/winbase/nf-winbase-getnamedpipeclientprocessid>
 109      It requires -D_WIN32_WINNT=_WIN32_WINNT_VISTA or higher.  */
 110   if (GetNamedPipeClientProcessIdFunc && QueryFullProcessImageNameFunc
 111       && GetNamedPipeClientProcessIdFunc (h, &processId))
 112     {
 113       /* OpenProcess
 114          <https://docs.microsoft.com/en-us/windows/desktop/api/processthreadsapi/nf-processthreadsapi-openprocess> */
 115       HANDLE processHandle =
 116         OpenProcess (PROCESS_QUERY_LIMITED_INFORMATION, FALSE, processId);
 117       if (processHandle != NULL)
 118         {
 119           char buf[1024];
 120           DWORD bufsize = sizeof (buf);
 121           /* The file name can be determined through
 122              GetProcessImageFileName
 123              <https://docs.microsoft.com/en-us/windows/desktop/api/psapi/nf-psapi-getprocessimagefilenamea>
 124              or
 125              QueryFullProcessImageName
 126              <https://docs.microsoft.com/en-us/windows/desktop/api/winbase/nf-winbase-queryfullprocessimagenamea>
 127              The former returns a file name in non-standard notation (it starts
 128              with '\Device\') and may require linking with psapi.dll.
 129              The latter is better, but requires -D_WIN32_WINNT=_WIN32_WINNT_VISTA
 130              or higher.  */
 131           if (QueryFullProcessImageNameFunc (processHandle, 0, buf, &bufsize))
 132             {
 133               if (strlen (buf) >= 11
 134                   && strcmp (buf + strlen (buf) - 11, "\\mintty.exe") == 0)
 135                 result = TRUE;
 136             }
 137           CloseHandle (processHandle);
 138         }
 139     }
 140   return result;
 141 }
 142 
 143 #if HAVE_MSVC_INVALID_PARAMETER_HANDLER
 144 static int
 145 _isatty_nothrow (int fd)
     /* [previous][next][first][last][top][bottom][index][help] */
 146 {
 147   int result;
 148 
 149   TRY_MSVC_INVAL
 150     {
 151       result = _isatty (fd);
 152     }
 153   CATCH_MSVC_INVAL
 154     {
 155       result = 0;
 156     }
 157   DONE_MSVC_INVAL;
 158 
 159   return result;
 160 }
 161 #else
 162 # define _isatty_nothrow _isatty
 163 #endif
 164 
 165 /* Determine whether FD refers to a console device.  Return 1 if yes.
 166    Return 0 and set errno if no. (ptsname_r relies on the errno value.)  */
 167 int
 168 isatty (int fd)
     /* [previous][next][first][last][top][bottom][index][help] */
 169 {
 170   HANDLE h = (HANDLE) _get_osfhandle (fd);
 171   if (h == INVALID_HANDLE_VALUE)
 172     {
 173       errno = EBADF;
 174       return 0;
 175     }
 176   /* _isatty (fd) tests whether GetFileType of the handle is FILE_TYPE_CHAR.
 177      But it does not set errno when it returns 0.  */
 178   if (_isatty_nothrow (fd))
 179     {
 180       if (IsConsoleHandle (h))
 181         return 1;
 182     }
 183   if (IsCygwinConsoleHandle (h))
 184     return 1;
 185   errno = ENOTTY;
 186   return 0;
 187 }

/* [previous][next][first][last][top][bottom][index][help] */