dnl -*- Autoconf -*-
dnl Copyright (C) 1993-2009, 2011, 2017-2020 Free Software Foundation, Inc.
dnl This file is free software, distributed under the terms of the GNU
dnl General Public License.  As a special exception to the GNU General
dnl Public License, this file may be distributed as part of a program
dnl that contains a configuration script generated by Autoconf, under
dnl the same distribution terms as the rest of that program.

dnl From Bruno Haible, Marcus Daniels, Sam Steingold.

AC_PREREQ([2.13])

AC_DEFUN([CL_FILECHARSET],
[
  AC_REQUIRE([AC_PROG_CC])
  AC_CACHE_CHECK([for the valid characters in filenames],
    [cl_cv_os_valid_filename_char],
    [dnl Create the subdirectory the test program will use for its files.
     mkdir conftestdir
     AC_RUN_IFELSE(
       [AC_LANG_PROGRAM([[
          #include "confdefs.h"
          #include <sys/types.h>
          #include <stdlib.h>
          /* Declare chdir(). */
          #ifdef HAVE_UNISTD_H
           #include <unistd.h>
          #endif
          #include <string.h>
          #include <stdio.h>
          /* Declare open(). */
          #include <fcntl.h>
          /* Declare opendir(), readdir(), closedir(). */
          #include <dirent.h>
          /* A small program which checks for each character whether or not it is
           * valid in filenames.
           * The actual result may depend on OS, its version, the file system
           * on which the test is run, and - on Windows - the system charset.
           * We test only the ASCII range (0x00..0x7F), because with non-ASCII
           * characters 1. our test is not prepared for multibyte encodings,
           * and 2. the result on Windows really depends on the system charset.
           */
          #define N 128
          ]],[[
          if (freopen("conftest.out", "wb", stdout) == NULL) return 1;
          {
            char legal[N];
            char filename[4];
            int i;
            if (chdir("conftestdir") < 0) return 1;
            for (i = 0; i < N; i++) legal[i] = 0;
            strcpy(filename,"a_z");
            for (i = 0; i < N; i++)
              if (i != '\0')
                {
                  filename[1] = i;
                  /* Determine whether the filename is valid: create a file
                   * and check that it is present afterwards, under the same name. */
                  {
                    int fd = open(filename, O_CREAT | O_RDWR, 0644);
                    if (fd >=0)
                      {
                        DIR* dirp = opendir(".");
                        if (dirp != (DIR*)0)
                          {
                            struct dirent * d;
                            while ((d = readdir(dirp)))
                              {
                                if (!strcmp(d->d_name,".")) continue;
                                if (!strcmp(d->d_name,"..")) continue;
                                if (!strncmp(d->d_name,".nfs",4)) continue;
                                if (!strcmp(d->d_name,filename)) legal[i] = 1;
                                /* Remove the file even if its name is something else. */
                                unlink(d->d_name);
                              }
                            closedir(dirp);
                          }
                        close(fd);
                      }
                  }
                }
            /* Output a boolean expression equivalent to legal[ch] (0 <= ch < N). */
            {
              int need_or = 0;
              int z;
              for (z = 0; z < N; )
                {
                  int x, y;
                  if (! legal[z]) { z++; continue; }
                  x = z;
                  if (need_or) printf(" || ");
                  z++;
                  if ((z < N) && legal[z])
                    {
                      do
                        {
                          do { z++; } while ((z < N) && legal[z]);
                          y = z-1;
                          z++;
                        }
                      while ((z < N) && legal[z]);
                      {
                        int premises = 0;
                        if (x > 0) premises++;
                        if (y < N-1) premises++;
                        for (i = x; i <= y; i++)
                          if (! legal[i])
                            premises++;
                        if (premises > 1) printf("(");
                        {
                          int need_and = 0;
                          if (x > 0) { printf("(ch >= %d)",x); need_and = 1; }
                          if (y < N-1)
                            {
                              if (need_and) printf(" && ");
                              printf("(ch <= %d)",y);
                              need_and = 1;
                            }
                          for (i = x; i <= y; i++)
                            if (! legal[i])
                              {
                                if (need_and) printf(" && ");
                                printf("(ch != %d)",i);
                                need_and = 1;
                              }
                          if (!need_and) printf("1");
                        }
                        if (premises > 1) printf(")");
                      }
                      z = y+1;
                    }
                  else
                    {
                      printf("(ch == %d)",x);
                      z++;
                    }
                  need_or = 1;
                }
              printf("\n");
            }
          }
          return ferror(stdout) || fclose(stdout);
          ]])
       ],
       [cl_cv_os_valid_filename_char=`cat conftest.out`],
       [cl_cv_os_valid_filename_char=''],
       [cl_cv_os_valid_filename_char=''])
     dnl clean up
     # Workaround a problem with NFS on Solaris 7, where unlink()ed files reappear
     # immediately under a different name and disappear only after 1. the process
     # doing readdir() has exited and 2. waiting a second or two.
     # Even "rm -rf conftestdir" goes into an endless loop, eating CPU time, under
     # these conditions.
     period=1
     while test -n "`ls conftestdir/.nfs* 2>/dev/null`"; do
       echo "waiting for NFS..."
       rm -f conftestdir/.nfs* 2>/dev/null
       sleep $period
       period=`expr 2 '*' $period`
     done
     # Now it's safe to do "rm -rf conftestdir".
     rm -rf conftestdir
     rm -f conftest.out
     if test -z "$cl_cv_os_valid_filename_char"; then
       cl_cv_os_valid_filename_charset="guessing 7-bit"
     else
       if test "$cl_cv_os_valid_filename_char" = '((ch >= 1) && (ch != 47))'; then
         cl_cv_os_valid_filename_charset="8-bit"
       else
         cl_cv_os_valid_filename_charset="7-bit"
       fi
     fi
    ])
  if test -n "$cl_cv_os_valid_filename_char"; then
    AC_DEFINE_UNQUOTED([VALID_FILENAME_CHAR], [$cl_cv_os_valid_filename_char],
      [expression in ch which is true if ch is a valid character in filenames])
  fi
])
