(root)/
tar-1.35/
gnu/
msvc-inval.h
       1  /* Invalid parameter handler for MSVC runtime libraries.
       2     Copyright (C) 2011-2023 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  #ifndef _MSVC_INVAL_H
      18  #define _MSVC_INVAL_H
      19  
      20  /* With MSVC runtime libraries with the "invalid parameter handler" concept,
      21     functions like fprintf(), dup2(), or close() crash when the caller passes
      22     an invalid argument.  But POSIX wants error codes (such as EINVAL or EBADF)
      23     instead.
      24     This file defines macros that turn such an invalid parameter notification
      25     into a non-local exit.  An error code can then be produced at the target
      26     of this exit.  You can thus write code like
      27  
      28       TRY_MSVC_INVAL
      29         {
      30           <Code that can trigger an invalid parameter notification
      31            but does not do 'return', 'break', 'continue', nor 'goto'.>
      32         }
      33       CATCH_MSVC_INVAL
      34         {
      35           <Code that handles an invalid parameter notification
      36            but does not do 'return', 'break', 'continue', nor 'goto'.>
      37         }
      38       DONE_MSVC_INVAL;
      39  
      40     This entire block expands to a single statement.
      41  
      42     The handling of invalid parameters can be done in three ways:
      43  
      44       * The default way, which is reasonable for programs (not libraries):
      45         AC_DEFINE([MSVC_INVALID_PARAMETER_HANDLING], [DEFAULT_HANDLING])
      46  
      47       * The way for libraries that make "hairy" calls (like close(-1), or
      48         fclose(fp) where fileno(fp) is closed, or simply getdtablesize()):
      49         AC_DEFINE([MSVC_INVALID_PARAMETER_HANDLING], [HAIRY_LIBRARY_HANDLING])
      50  
      51       * The way for libraries that make no "hairy" calls:
      52         AC_DEFINE([MSVC_INVALID_PARAMETER_HANDLING], [SANE_LIBRARY_HANDLING])
      53   */
      54  
      55  /* This file uses HAVE_MSVC_INVALID_PARAMETER_HANDLER.  */
      56  #if !_GL_CONFIG_H_INCLUDED
      57   #error "Please include config.h first."
      58  #endif
      59  
      60  #define DEFAULT_HANDLING       0
      61  #define HAIRY_LIBRARY_HANDLING 1
      62  #define SANE_LIBRARY_HANDLING  2
      63  
      64  #if HAVE_MSVC_INVALID_PARAMETER_HANDLER \
      65      && !(MSVC_INVALID_PARAMETER_HANDLING == SANE_LIBRARY_HANDLING)
      66  /* A native Windows platform with the "invalid parameter handler" concept,
      67     and either DEFAULT_HANDLING or HAIRY_LIBRARY_HANDLING.  */
      68  
      69  # if MSVC_INVALID_PARAMETER_HANDLING == DEFAULT_HANDLING
      70  /* Default handling.  */
      71  
      72  #  ifdef __cplusplus
      73  extern "C" {
      74  #  endif
      75  
      76  /* Ensure that the invalid parameter handler in installed that just returns.
      77     Because we assume no other part of the program installs a different
      78     invalid parameter handler, this solution is multithread-safe.  */
      79  extern void gl_msvc_inval_ensure_handler (void);
      80  
      81  #  ifdef __cplusplus
      82  }
      83  #  endif
      84  
      85  #  define TRY_MSVC_INVAL \
      86       do                                                                        \
      87         {                                                                       \
      88           gl_msvc_inval_ensure_handler ();                                      \
      89           if (1)
      90  #  define CATCH_MSVC_INVAL \
      91           else
      92  #  define DONE_MSVC_INVAL \
      93         }                                                                       \
      94       while (0)
      95  
      96  # else
      97  /* Handling for hairy libraries.  */
      98  
      99  #  include <excpt.h>
     100  
     101  /* Gnulib can define its own status codes, as described in the page
     102     "Raising Software Exceptions" on microsoft.com
     103     <https://docs.microsoft.com/en-us/cpp/cpp/raising-software-exceptions>.
     104     Our status codes are composed of
     105       - 0xE0000000, mandatory for all user-defined status codes,
     106       - 0x474E550, a API identifier ("GNU"),
     107       - 0, 1, 2, ..., used to distinguish different status codes from the
     108         same API.  */
     109  #  define STATUS_GNULIB_INVALID_PARAMETER (0xE0000000 + 0x474E550 + 0)
     110  
     111  #  if defined _MSC_VER
     112  /* A compiler that supports __try/__except, as described in the page
     113     "try-except statement" on microsoft.com
     114     <https://docs.microsoft.com/en-us/cpp/cpp/try-except-statement>.
     115     With __try/__except, we can use the multithread-safe exception handling.  */
     116  
     117  #   ifdef __cplusplus
     118  extern "C" {
     119  #   endif
     120  
     121  /* Ensure that the invalid parameter handler in installed that raises a
     122     software exception with code STATUS_GNULIB_INVALID_PARAMETER.
     123     Because we assume no other part of the program installs a different
     124     invalid parameter handler, this solution is multithread-safe.  */
     125  extern void gl_msvc_inval_ensure_handler (void);
     126  
     127  #   ifdef __cplusplus
     128  }
     129  #   endif
     130  
     131  #   define TRY_MSVC_INVAL \
     132        do                                                                       \
     133          {                                                                      \
     134            gl_msvc_inval_ensure_handler ();                                     \
     135            __try
     136  #   define CATCH_MSVC_INVAL \
     137            __except (GetExceptionCode () == STATUS_GNULIB_INVALID_PARAMETER     \
     138                      ? EXCEPTION_EXECUTE_HANDLER                                \
     139                      : EXCEPTION_CONTINUE_SEARCH)
     140  #   define DONE_MSVC_INVAL \
     141          }                                                                      \
     142        while (0)
     143  
     144  #  else
     145  /* Any compiler.
     146     We can only use setjmp/longjmp.  */
     147  
     148  #   include <setjmp.h>
     149  
     150  #   ifdef __cplusplus
     151  extern "C" {
     152  #   endif
     153  
     154  struct gl_msvc_inval_per_thread
     155  {
     156    /* The restart that will resume execution at the code between
     157       CATCH_MSVC_INVAL and DONE_MSVC_INVAL.  It is enabled only between
     158       TRY_MSVC_INVAL and CATCH_MSVC_INVAL.  */
     159    jmp_buf restart;
     160  
     161    /* Tells whether the contents of restart is valid.  */
     162    int restart_valid;
     163  };
     164  
     165  /* Ensure that the invalid parameter handler in installed that passes
     166     control to the gl_msvc_inval_restart if it is valid, or raises a
     167     software exception with code STATUS_GNULIB_INVALID_PARAMETER otherwise.
     168     Because we assume no other part of the program installs a different
     169     invalid parameter handler, this solution is multithread-safe.  */
     170  extern void gl_msvc_inval_ensure_handler (void);
     171  
     172  /* Return a pointer to the per-thread data for the current thread.  */
     173  extern struct gl_msvc_inval_per_thread *gl_msvc_inval_current (void);
     174  
     175  #   ifdef __cplusplus
     176  }
     177  #   endif
     178  
     179  #   define TRY_MSVC_INVAL \
     180        do                                                                       \
     181          {                                                                      \
     182            struct gl_msvc_inval_per_thread *msvc_inval_current;                 \
     183            gl_msvc_inval_ensure_handler ();                                     \
     184            msvc_inval_current = gl_msvc_inval_current ();                       \
     185            /* First, initialize gl_msvc_inval_restart.  */                      \
     186            if (setjmp (msvc_inval_current->restart) == 0)                       \
     187              {                                                                  \
     188                /* Then, mark it as valid.  */                                   \
     189                msvc_inval_current->restart_valid = 1;
     190  #   define CATCH_MSVC_INVAL \
     191                /* Execution completed.                                          \
     192                   Mark gl_msvc_inval_restart as invalid.  */                    \
     193                msvc_inval_current->restart_valid = 0;                           \
     194              }                                                                  \
     195            else                                                                 \
     196              {                                                                  \
     197                /* Execution triggered an invalid parameter notification.        \
     198                   Mark gl_msvc_inval_restart as invalid.  */                    \
     199                msvc_inval_current->restart_valid = 0;
     200  #   define DONE_MSVC_INVAL \
     201              }                                                                  \
     202          }                                                                      \
     203        while (0)
     204  
     205  #  endif
     206  
     207  # endif
     208  
     209  #else
     210  /* A platform that does not need to the invalid parameter handler,
     211     or when SANE_LIBRARY_HANDLING is desired.  */
     212  
     213  /* The braces here avoid GCC warnings like
     214     "warning: suggest explicit braces to avoid ambiguous 'else'".  */
     215  # define TRY_MSVC_INVAL \
     216      do                                                                         \
     217        {                                                                        \
     218          if (1)
     219  # define CATCH_MSVC_INVAL \
     220          else
     221  # define DONE_MSVC_INVAL \
     222        }                                                                        \
     223      while (0)
     224  
     225  #endif
     226  
     227  #endif /* _MSVC_INVAL_H */