/* Portability cruft.  Include after config.h and sys/types.h.
   Copyright 1996, 1998-2000, 2007, 2009-2016 Free Software Foundation, Inc.

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 3, or (at your option)
   any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
   02110-1301, USA.  */

#ifndef GREP_SYSTEM_H
#define GREP_SYSTEM_H 1

#include <fcntl.h>
#include <unistd.h>
#include <errno.h>

#include "binary-io.h"
#include "configmake.h"
#include "dirname.h"
#include "ignore-value.h"
#include "minmax.h"
#include "same-inode.h"

#include <stdlib.h>
#include <stddef.h>
#include <limits.h>
#include <string.h>
#include <ctype.h>

#if O_BINARY
# ifdef __DJGPP__
/* MS-DOS and similar non-Posix systems have some peculiarities:
    - they use both `/' and `\\' as directory separator in file names;
    - they can have a drive letter X: prepended to a file name;
   These are all parameterized here.  */

#  if defined (__GNUC__) && (__GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 8))
#   define __gnuc_extension__  __extension__
#  else
#   define __gnuc_extension__
#  endif
#  include <libc/unconst.h>
#  define IS_DIR_SEPARATOR(c)  ((c) == '/' || (c) == '\\' || (c) == ':')
#  define STRIP_FULL_PATH_AND_EXTENSION(file_name)     \
   (__gnuc_extension__                                 \
     ({                                                \
        char *_dst, *_src;                             \
        _dst = _src = unconst((file_name), char *);    \
        while (*_src++)                                \
          ;                                            \
        while ((_src - _dst) && (*--_src != '.'))      \
          ;                                            \
        for (*_src = '\0'; (_src - _dst); _src--)      \
          if (IS_DIR_SEPARATOR(*_src))                 \
            break;                                     \
        if (_src - _dst)                               \
          while ((*_dst++ = *++_src))                  \
            ;                                          \
        (file_name);                                   \
     })                                                \
   )
#  define STRIP_EXTENSION(file_name)                   \
   (__gnuc_extension__                                 \
     ({                                                \
        char *_begin, *_end;                           \
        _begin = _end = unconst((file_name), char *);  \
        while (*_end++)                                \
          ;                                            \
        while ((_end - _begin) && (*--_end != '.'))    \
          ;                                            \
        if (*_end == '.')                              \
          *_end = '\0';                                \
        (file_name);                                   \
     })                                                \
   )
#  define CANONICALIZE_PATH(path)                      \
   (__gnuc_extension__                                 \
     ({                                                \
        if ((path))                                    \
        {                                              \
          char *_p = unconst((path), char *);          \
          for (; *_p; _p++)                            \
            if (*_p == '\\')                           \
              *_p = '/';                               \
        }                                              \
        (path);                                        \
     })                                                \
   )
# else  /* !__DJGPP__  */
#  define STRIP_FULL_PATH_AND_EXTENSION(file_name)  (file_name)
#  define STRIP_EXTENSION(file_name)                (file_name)
#  define CANONICALIZE_PATH(path)                   (path)
# endif  /* !__DJGPP__  */
#endif

enum { EXIT_TROUBLE = 2 };

#include <gettext.h>
#define N_(String) gettext_noop(String)
#define _(String) gettext(String)

#include <locale.h>

#ifndef initialize_main
# define initialize_main(argcp, argvp)
#endif

#include "unlocked-io.h"

_GL_INLINE_HEADER_BEGIN
#ifndef SYSTEM_INLINE
# define SYSTEM_INLINE _GL_INLINE
#endif

#define STREQ(a, b) (strcmp (a, b) == 0)

/* Convert a possibly-signed character to an unsigned character.  This is
   a bit safer than casting to unsigned char, since it catches some type
   errors that the cast doesn't.  */
SYSTEM_INLINE unsigned char
to_uchar (char ch)
{
  return ch;
}

_GL_INLINE_HEADER_END

#ifndef __has_feature
# define __has_feature(F) false
#endif

#if defined __SANITIZE_ADDRESS__ || __has_feature (address_sanitizer)
# define HAVE_ASAN 1
#else
# define HAVE_ASAN 0
#endif

#if HAVE_ASAN

/* Mark memory region [addr, addr+size) as unaddressable.
   This memory must be previously allocated by the user program.  Accessing
   addresses in this region from instrumented code is forbidden until
   this region is unpoisoned.  This function is not guaranteed to poison
   the whole region - it may poison only a subregion of [addr, addr+size)
   due to ASan alignment restrictions.
   Method is NOT thread-safe in the sense that no two threads can
   (un)poison memory in the same memory region simultaneously.  */
void __asan_poison_memory_region (void const volatile *addr, size_t size);

/* Mark memory region [addr, addr+size) as addressable.
   This memory must be previously allocated by the user program.  Accessing
   addresses in this region is allowed until this region is poisoned again.
   This function may unpoison a superregion of [addr, addr+size) due to
   ASan alignment restrictions.
   Method is NOT thread-safe in the sense that no two threads can
   (un)poison memory in the same memory region simultaneously.  */
void __asan_unpoison_memory_region (void const volatile *addr, size_t size);

#else

static _GL_UNUSED void
__asan_poison_memory_region (void const volatile *addr, size_t size) { }
static _GL_UNUSED void
__asan_unpoison_memory_region (void const volatile *addr, size_t size) { }
#endif

#endif
