diff --git a/ccomp/runtime/pats_ccomp_typedefs.h b/ccomp/runtime/pats_ccomp_typedefs.h index 340ba0c297..8a42c0736c 100644 --- a/ccomp/runtime/pats_ccomp_typedefs.h +++ b/ccomp/runtime/pats_ccomp_typedefs.h @@ -13,12 +13,12 @@ ** the terms of the GNU GENERAL PUBLIC LICENSE (GPL) as published by the ** Free Software Foundation; either version 3, or (at your option) any ** later version. -** +** ** ATS 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 ATS; see the file COPYING. If not, please write to the ** Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA @@ -56,8 +56,15 @@ typedef void atsvoid_t0ype ; typedef int atstype_int ; typedef unsigned int atstype_uint ; +#if _WIN32 +// in Windows, sizeof(long) = sizeof(int), +// but we need more space than 32-bit +typedef long long int atstype_lint ; +typedef unsigned long long int atstype_ulint ; +#else typedef long int atstype_lint ; typedef unsigned long int atstype_ulint ; +#endif typedef long long int atstype_llint ; typedef unsigned long long int atstype_ullint ; diff --git a/doc/EXAMPLE/INTRO/areverse.dats b/doc/EXAMPLE/INTRO/areverse.dats index ea72f113da..c6c16efcd4 100644 --- a/doc/EXAMPLE/INTRO/areverse.dats +++ b/doc/EXAMPLE/INTRO/areverse.dats @@ -64,13 +64,23 @@ _(*RG*) = "{$MYTESTING}/DATS/randgen.dats" // #include // +#if _WIN32 +// NOTE: +// 1. replace srand48(seed) by srand(seed) +// 2. replace drand48() by (double(rand()) / RAND_MAX) +#else extern void srand48 (long int) ; // in [stdlib.h] extern double drand48 (/*void*/) ; // in [stdlib.h] +#endif // atsvoid_t0ype srand48_with_time () { +#if _WIN32 + srand(time(0)) ; return ; +#else srand48(time(0)) ; return ; +#endif } %} extern diff --git a/doc/EXAMPLE/MISC/foreach_getline.dats b/doc/EXAMPLE/MISC/foreach_getline.dats index b40450a303..8897593523 100644 --- a/doc/EXAMPLE/MISC/foreach_getline.dats +++ b/doc/EXAMPLE/MISC/foreach_getline.dats @@ -29,6 +29,71 @@ absvtype line = ptr (* ****** ****** *) +%{ + +#if _WIN32 + + +#include /* EINVAL */ + +/* The original code is public domain -- Will Hartung 4/9/09 */ +/* Modifications, public domain as well, by Antti Haapala, 11/10/17 */ +/* source: https://stackoverflow.com/questions/735126/are-there-alternate-implementations-of-gnu-getline-interface */ + +ssize_t getline(char **lineptr, size_t *n, FILE *stream) { + size_t pos; + int c; + + if (lineptr == NULL || stream == NULL || n == NULL) { + errno = EINVAL; + return -1; + } + + c = fgetc(stream); + if (c == EOF) { + return -1; + } + + if (*lineptr == NULL) { + *lineptr = malloc(128); + if (*lineptr == NULL) { + return -1; + } + *n = 128; + } + + pos = 0; + while(c != EOF) { + if (pos + 1 >= *n) { + size_t new_size = *n + (*n >> 2); + if (new_size < 128) { + new_size = 128; + } + char *new_ptr = realloc(*lineptr, new_size); + if (new_ptr == NULL) { + return -1; + } + *n = new_size; + *lineptr = new_ptr; + } + + ((unsigned char *)(*lineptr))[pos ++] = c; + if (c == '\n') { + break; + } + c = fgetc(stream); + } + + (*lineptr)[pos] = '\0'; + return pos; +} + +#endif + +%} + +(* ****** ****** *) + extern fun{} line_nil(): line diff --git a/doc/EXAMPLE/MISC/wclines.dats b/doc/EXAMPLE/MISC/wclines.dats index 8e2f9f1acd..a697673ceb 100644 --- a/doc/EXAMPLE/MISC/wclines.dats +++ b/doc/EXAMPLE/MISC/wclines.dats @@ -25,9 +25,28 @@ staload "libats/libc/SATS/stdio.sats" (* ****** ****** *) %{^ +#if _WIN32 + +static +void +*rawmemchr(const void *s, int c) { + if (s == NULL) + return NULL ; + char* p = (char*)s; + while (1) { + int c1 = *p; + if (c1 == c) + return (void*)p ; + p++; + } + return NULL; /* deadcode! */ +} + +#else extern void *rawmemchr(const void *s, int c); +#endif #define atslib_rawmemchr rawmemchr %} extern diff --git a/libats/DATS/linmap_skiplist.dats b/libats/DATS/linmap_skiplist.dats index e9ba696565..271be47661 100644 --- a/libats/DATS/linmap_skiplist.dats +++ b/libats/DATS/linmap_skiplist.dats @@ -61,7 +61,12 @@ stadef mytkind = $extkind"atslib_linmap_skiplist" // // HX: it is in stdlib.h // +#if _WIN32 +extern void srand (unsigned int); +#define srand48 srand +#else extern void srand48 (long int); +#endif // %} typedef time_t = $extype"time_t" diff --git a/libats/libc/CATS/arpa/inet.cats b/libats/libc/CATS/arpa/inet.cats index 70b3afed55..e6470c7056 100644 --- a/libats/libc/CATS/arpa/inet.cats +++ b/libats/libc/CATS/arpa/inet.cats @@ -40,8 +40,12 @@ /* ****** ****** */ // +#if _WIN32 +// FIXME: error? +#else #include #include +#endif // /* ****** ****** */ @@ -62,6 +66,9 @@ // /* ****** ****** */ +#if _WIN32 +// FIXME: error? +#else extern int inet_aton @@ -84,6 +91,7 @@ atslib_libats_libc_inet_aton return (rtn ? atsbool_true : atsbool_false) ; // } // end of [atslib_libats_libc_inet_aton] +#endif /* ****** ****** */ diff --git a/libats/libc/CATS/dirent.cats b/libats/libc/CATS/dirent.cats index 94e9f5c610..4db2a84a2e 100644 --- a/libats/libc/CATS/dirent.cats +++ b/libats/libc/CATS/dirent.cats @@ -40,8 +40,12 @@ /* ****** ****** */ +#if _WIN32 +#include "mingw/dirent.h" +#else #include #include // HX: after sys/types +#endif /* ****** ****** */ diff --git a/libats/libc/CATS/fcntl.cats b/libats/libc/CATS/fcntl.cats index 472322e641..1447661b02 100644 --- a/libats/libc/CATS/fcntl.cats +++ b/libats/libc/CATS/fcntl.cats @@ -64,10 +64,14 @@ atslib_libats_libc_fcntlflags_lor(x1, x2) ((x1)|(x2)) /* ****** ****** */ +#if _WIN32 +// FIXME: error out? +#else #define \ atslib_libats_libc_fcntl_getfl(fd) fcntl(fd, F_GETFL) #define \ atslib_libats_libc_fcntl_setfl(fd, flags) fcntl(fd, F_SETFL, flags) +#endif /* ****** ****** */ diff --git a/libats/libc/CATS/fnmatch.cats b/libats/libc/CATS/fnmatch.cats index dc62bf1641..e5c4e280cd 100644 --- a/libats/libc/CATS/fnmatch.cats +++ b/libats/libc/CATS/fnmatch.cats @@ -40,7 +40,11 @@ /* ****** ****** */ +#if _WIN32 +#include "mingw/fnmatch.h" +#else #include +#endif /* ****** ****** */ diff --git a/libats/libc/CATS/malloc.cats b/libats/libc/CATS/malloc.cats index b1e5b1820b..970620f28e 100644 --- a/libats/libc/CATS/malloc.cats +++ b/libats/libc/CATS/malloc.cats @@ -40,16 +40,49 @@ /* ****** ****** */ +#if _WIN32 +#include +#else #include +#endif /* ****** ****** */ +#if _WIN32 + +static +int atslib_libats_libc_mallopt(int param, int value) { + return 0; // error +} +static +int atslib_libats_libc_malloc_trim(size_t pad) { + return 0; // unable to release any memory back to system +} +static +size_t atslib_libats_libc_malloc_usable_size(void *ptr) { + return 0; // no usable bytes in the pointer that we know of... +} +static +void atslib_libats_libc_malloc_stats() { + fprintf(stderr, "malloc_stats() is not implemented"); +} +static +void *atslib_libats_libc_malloc_get_state() { + return NULL; // error: unable to allocate memory for storing state +} +static +int atslib_libats_libc_malloc_set_state(void *state) { + return -1; // error: unable to restore state +} + +#else #define atslib_libats_libc_mallopt mallopt #define atslib_libats_libc_malloc_trim malloc_trim #define atslib_libats_libc_malloc_usable_size malloc_usable_size #define atslib_libats_libc_malloc_stats malloc_stats #define atslib_libats_libc_malloc_get_state malloc_get_state #define atslib_libats_libc_malloc_set_state malloc_set_state +#endif /* ****** ****** */ diff --git a/libats/libc/CATS/netinet/in.cats b/libats/libc/CATS/netinet/in.cats index d6463570d1..cc240f8431 100644 --- a/libats/libc/CATS/netinet/in.cats +++ b/libats/libc/CATS/netinet/in.cats @@ -39,21 +39,32 @@ #define ATSLIB_LIBATS_LIBC_NETINET_IN_CATS /* ****** ****** */ +#if _WIN32 +// FIXME: error? +#else // #include #include // +#endif /* ****** ****** */ // +#if _WIN32 +// FIXME: error? +#else typedef struct in_addr in_addr_struct; typedef struct in6_addr in6_addr_struct; +#endif // /* ****** ****** */ // +#if _WIN32 +// FIXME: error? +#else typedef struct sockaddr_in sockaddr_in_struct ; @@ -67,6 +78,7 @@ atslib_libats_libc_socklen_in \ #define \ atslib_libats_libc_socklen_in6 \ (sizeof(sockaddr_in6_struct)) +#endif // /* ****** ****** */ @@ -77,6 +89,9 @@ atslib_libats_libc_in_port_nbo_uint(nport) htons(nport) /* ****** ****** */ +#if _WIN32 +// FIXME: error? +#else ATSinline() in_addr_t atslib_libats_libc_in_addr_hbo2nbo @@ -85,6 +100,7 @@ atslib_libats_libc_in_addr_hbo2nbo return htonl(addr_hbo) ; } /* end of [atslib_libats_libc_in_addr_hbo2nbo] */ +#endif /* ****** ****** */ diff --git a/libats/libc/CATS/stdlib.cats b/libats/libc/CATS/stdlib.cats index b9a13a9e24..f8dcf1a63d 100644 --- a/libats/libc/CATS/stdlib.cats +++ b/libats/libc/CATS/stdlib.cats @@ -149,15 +149,29 @@ strtod((char*)(nptr), (char**)(endptr)) /* ****** ****** */ +#if _WIN32 +#define atslib_libats_libc_random rand +#define atslib_libats_libc_srandom srand +#else #define atslib_libats_libc_random random #define atslib_libats_libc_srandom srandom +#endif /* ****** ****** */ // #define atslib_libats_libc_seed48 seed48 +#if _WIN32 +#define atslib_libats_libc_srand48 srand +#else #define atslib_libats_libc_srand48 srand48 +#endif + // +#if _WIN32 +#define atslib_libats_libc_drand48() ((double)(rand()) / RAND_MAX) +#else #define atslib_libats_libc_drand48 drand48 +#endif #define atslib_libats_libc_erand48 erand48 #define atslib_libats_libc_lrand48 lrand48 #define atslib_libats_libc_nrand48 nrand48 diff --git a/libats/libc/CATS/string.cats b/libats/libc/CATS/string.cats index 6e39776e0e..1539081baf 100644 --- a/libats/libc/CATS/string.cats +++ b/libats/libc/CATS/string.cats @@ -113,7 +113,11 @@ /* ****** ****** */ #define atslib_libats_libc_strerror strerror +#if _WIN32 +#define atslib_libats_libc_strerror_r(err_code, buf, buflen) (!strerror_s(buf, buflen, err_code)) +#else #define atslib_libats_libc_strerror_r strerror_r +#endif /* ****** ****** */ diff --git a/libats/libc/CATS/sys/socket.cats b/libats/libc/CATS/sys/socket.cats index f946986147..a25ebe8f5b 100644 --- a/libats/libc/CATS/sys/socket.cats +++ b/libats/libc/CATS/sys/socket.cats @@ -42,8 +42,12 @@ ATSLIB_LIBATS_LIBC_CATS_SYS_SOCKET /* ****** ****** */ // +#if _WIN32 +// FIXME: error? +#else #include #include +#endif // /* ****** ****** */ // @@ -68,6 +72,9 @@ atslib_libats_libc_socket_AF_type socket_AF_type atslib_libats_libc_socket_PF_type socket_PF_type /* ****** ****** */ +#if _WIN32 +// FIXME: error? +#else // #define \ atslib_libats_libc_bind_err(fd, sa, len) \ @@ -80,6 +87,7 @@ atslib_libats_libc_bind_exn int sockfd, atstype_ptr sa, socklen_t salen ); // end of [atslib_libats_libc_bind_exn] // +#endif /* ****** ****** */ // #define \ @@ -90,6 +98,9 @@ void atslib_libats_libc_listen_exn(int sockfd, int listenqsz); // /* ****** ****** */ +#if _WIN32 +// FIXME: error? +#else // #define \ atslib_libats_libc_connect_err(fd, sa, len) \ @@ -102,7 +113,11 @@ atslib_libats_libc_connect_exn int sockfd, atstype_ptr sa, socklen_t salen ); // end of [atslib_libats_libc_connect_exn] // +#endif /* ****** ****** */ +#if _WIN32 +// FIXME: error? +#else // #define \ atslib_libats_libc_accept_err(fd, sa, len) \ @@ -111,6 +126,7 @@ atslib_libats_libc_accept_err(fd, sa, len) \ #define \ atslib_libats_libc_accept_null_err(fd) atslib_libats_libc_accept_err(fd, 0, 0) // +#endif /* ****** ****** */ #define atslib_libats_libc_socket_close(fd) close(fd) diff --git a/libats/libc/CATS/sys/socket_in.cats b/libats/libc/CATS/sys/socket_in.cats index dd9dd7fb7d..56ae5b3f3b 100644 --- a/libats/libc/CATS/sys/socket_in.cats +++ b/libats/libc/CATS/sys/socket_in.cats @@ -42,8 +42,12 @@ ATSLIB_LIBATS_LIBC_CATS_SYS_SOCKET_IN /* ****** ****** */ // +#if _WIN32 +// FIXME: error? +#else #include #include +#endif // /* ****** ****** */ // @@ -55,6 +59,9 @@ void *memset (void *p, int c, size_t n) ; // /* ****** ****** */ +#if _WIN32 +// FIXME: error? +#else ATSinline() atsvoid_t0ype atslib_libats_libc_sockaddr_in_init @@ -68,6 +75,7 @@ atslib_libats_libc_sockaddr_in_init sa2->sin_addr.s_addr = inp ; sa2->sin_port = port ; } // end of [atslib_libats_libc_sockaddr_in_init] +#endif /* ****** ****** */ diff --git a/libats/libc/CATS/sys/types.cats b/libats/libc/CATS/sys/types.cats index 2abd7eb4a9..8381215f4a 100644 --- a/libats/libc/CATS/sys/types.cats +++ b/libats/libc/CATS/sys/types.cats @@ -74,6 +74,10 @@ typedef off_t atslib_libats_libc_off_type ; /* ****** ****** */ +#ifdef _WIN32 +typedef int uid_t; +typedef int gid_t; +#endif typedef pid_t atslib_libats_libc_pid_type ; typedef uid_t atslib_libats_libc_uid_type ; typedef gid_t atslib_libats_libc_gid_type ; diff --git a/libats/libc/DATS/fcntl.dats b/libats/libc/DATS/fcntl.dats index b93f685433..d9bb31131b 100644 --- a/libats/libc/DATS/fcntl.dats +++ b/libats/libc/DATS/fcntl.dats @@ -48,6 +48,9 @@ staload "libats/libc/SATS/fcntl.sats" (* ****** ****** *) %{$ +#if _WIN32 +// FIXME: error out? +#else extern atstype_int atslib_libats_libc_fildes_iget_int @@ -59,6 +62,7 @@ atslib_libats_libc_fildes_iget_int if (flags < 0) return -1 ; // [fd2] not in use return fd ; } // end of [atslib_libats_libc_fildes_iget_int] +#endif %} (* ****** ****** *) diff --git a/libats/libc/DATS/sys/socket.dats b/libats/libc/DATS/sys/socket.dats index bc1b731b68..a310596c3e 100644 --- a/libats/libc/DATS/sys/socket.dats +++ b/libats/libc/DATS/sys/socket.dats @@ -61,6 +61,9 @@ staload UN = "prelude/SATS/unsafe.sats" (* ****** ****** *) %{$ +#if _WIN32 +// FIXME: error? +#else ATSextern() atstype_int atslib_libats_libc_socket_AF_type_exn @@ -73,11 +76,15 @@ atslib_libats_libc_socket_AF_type_exn if(0 > fildes) ATSLIBfailexit("socket") ; // HX: failure return fildes; } // end of [atslib_libats_libc_socket_AF_type_exn] +#endif %} // end of [%{] (* ****** ****** *) %{$ +#if _WIN32 +// FIXME: error? +#else ATSextern() atsvoid_t0ype atslib_libats_libc_bind_exn @@ -91,11 +98,15 @@ atslib_libats_libc_bind_exn if(0 > err) ATSLIBfailexit("bind") ; // HX: failure return; } // end of [atslib_libats_libc_bind_exn] +#endif %} // end of [%{] (* ****** ****** *) %{$ +#if _WIN32 +// FIXME: error? +#else ATSextern() atsvoid_t0ype atslib_libats_libc_listen_exn @@ -108,11 +119,15 @@ atslib_libats_libc_listen_exn if(0 > err) ATSLIBfailexit("listen") ; // HX: failure return; } // end of [atslib_libats_libc_listen_exn] +#endif %} // end of [%{] (* ****** ****** *) %{$ +#if _WIN32 +// FIXME: error? +#else ATSextern() atsvoid_t0ype atslib_libats_libc_connect_exn @@ -126,11 +141,15 @@ atslib_libats_libc_connect_exn if(0 > err) ATSLIBfailexit("connect") ; // HX: failure return; } // end of [atslib_libats_libc_connect_exn] +#endif %} // end of [%{] (* ****** ****** *) %{$ +#if _WIN32 +// FIXME: error? +#else ATSextern() atsvoid_t0ype atslib_libats_libc_socket_close_exn @@ -143,11 +162,15 @@ atslib_libats_libc_socket_close_exn if(0 > err) ATSLIBfailexit("socket_close") ; // HX: failure return; } // end of [atslib_libats_libc_socket_close_exn] +#endif %} // end of [%{] (* ****** ****** *) %{$ +#if _WIN32 +// FIXME: error? +#else ATSextern() atsvoid_t0ype atslib_libats_libc_shutdown_exn @@ -160,6 +183,7 @@ atslib_libats_libc_shutdown_exn if(0 > err) ATSLIBfailexit("shutdown") ; // HX: failure return; } // end of [atslib_libats_libc_shutdown_exn] +#endif %} // end of [%{] (* ****** ****** *) diff --git a/libats/libc/DATS/sys/socket_in.dats b/libats/libc/DATS/sys/socket_in.dats index 8428e843d9..8b0988d178 100644 --- a/libats/libc/DATS/sys/socket_in.dats +++ b/libats/libc/DATS/sys/socket_in.dats @@ -62,6 +62,9 @@ staload (* ****** ****** *) %{$ +#if _WIN32 +// FIXME: error? +#else ATSextern() atsvoid_t0ype atslib_libats_libc_bind_in_exn @@ -77,11 +80,15 @@ atslib_libats_libc_bind_in_exn if(0 > err) ATSLIBfailexit("bind"); return; } // end of [atslib_libats_libc_bind_in_exn] +#endif %} // end of [%{] (* ****** ****** *) %{$ +#if _WIN32 +// FIXME: error? +#else ATSextern() atsvoid_t0ype atslib_libats_libc_connect_in_exn @@ -97,6 +104,7 @@ atslib_libats_libc_connect_in_exn if(0 > err) ATSLIBfailexit("connect"); return; } // end of [atslib_libats_libc_connect_in_exn] +#endif %} // end of [%{] (* ****** ****** *) diff --git a/libats/libc/DATS/unistd.dats b/libats/libc/DATS/unistd.dats index 77ba09eaed..f622e2c3da 100644 --- a/libats/libc/DATS/unistd.dats +++ b/libats/libc/DATS/unistd.dats @@ -70,6 +70,9 @@ atslib_libats_libc_close_exn (* ****** ****** *) %{$ +#if _WIN32 +// FIXME: error out? +#else extern atstype_int atslib_libats_libc_dup2_fildes @@ -87,6 +90,7 @@ atslib_libats_libc_dup2_fildes return atslib_libats_libc_dup2(fd, fd2) ; // } /* end of [atslib_libats_libc_dup2_fildes] */ +#endif %} (* ****** ****** *) @@ -123,6 +127,9 @@ atslib_libats_libc_getcwd_gc ( (* ****** ****** *) %{$ +#if _WIN32 +// FIXME: error? +#else extern atstype_strptr atslib_libats_libc_getlogin_r_gc ( @@ -148,6 +155,7 @@ atslib_libats_libc_getlogin_r_gc ( return (char*)0 ; // } /* end of [atslib_libats_libc_getlogin_r_gc] */ +#endif %} (* ****** ****** *) @@ -169,6 +177,9 @@ atslib_libats_libc_rmdir_exn (* ****** ****** *) %{$ +#if _WIN32 +// FIXME: error? +#else extern atsvoid_t0ype atslib_libats_libc_link_exn @@ -180,11 +191,15 @@ atslib_libats_libc_link_exn if (0 > err) ATSLIBfailexit("link") ; return ; } /* end of [atslib_libats_libc_link_exn] */ +#endif %} (* ****** ****** *) %{$ +#if _WIN32 +// FIXME: error? +#else extern atsvoid_t0ype atslib_libats_libc_unlink_exn @@ -196,11 +211,15 @@ atslib_libats_libc_unlink_exn if (0 > err) ATSLIBfailexit("unlink") ; return ; } /* end of [atslib_libats_libc_unlink_exn] */ +#endif %} (* ****** ****** *) %{$ +#if _WIN32 +// FIXME: error? +#else extern atsvoid_t0ype atslib_libats_libc_symlink_exn @@ -212,11 +231,15 @@ atslib_libats_libc_symlink_exn if (0 > err) ATSLIBfailexit("symlink") ; return ; } /* end of [atslib_libats_libc_symlink_exn] */ +#endif %} (* ****** ****** *) %{$ +#if _WIN32 +// FIXME: error? +#else extern atstype_strptr atslib_libats_libc_readlink_gc @@ -250,6 +273,7 @@ atslib_libats_libc_readlink_gc return (char*)0 ; // HX: deadcode // } /* end of [atslib_libats_libc_readlink_gc] */ +#endif %} (* ****** ****** *) diff --git a/mingw/.gitignore b/mingw/.gitignore new file mode 100644 index 0000000000..8ae1f025dd --- /dev/null +++ b/mingw/.gitignore @@ -0,0 +1,4 @@ +# ignore everything that is fetched +dirent.h +gc/ +gc-*.tar.gz diff --git a/mingw/Makefile b/mingw/Makefile new file mode 100644 index 0000000000..781e2322b5 --- /dev/null +++ b/mingw/Makefile @@ -0,0 +1,7 @@ +all: dirent.h packages + +dirent.h: + wget https://raw.githubusercontent.com/tronkko/dirent/4677a335cb1cf6f76b0a28d44fd5e1ae7c4728e1/include/dirent.h + +packages: + pacman -Syu mingw-w64-x86_64-dlfcn mingw-w64-x86_64-gc diff --git a/mingw/README.md b/mingw/README.md new file mode 100644 index 0000000000..3b3a796cfe --- /dev/null +++ b/mingw/README.md @@ -0,0 +1,9 @@ +# mingw + +This directory contains some Windows-specific third-party source code +that is intended to provide solutions to some, but not all, +portability woes. + +Please run `make` in an MSYS2 shell to fetch all third-party +dependencies from their respective authors. We strongly insist that +you have a working `wget` utility on your system (comes with MSYS2). diff --git a/mingw/fnmatch.h b/mingw/fnmatch.h new file mode 100644 index 0000000000..bc2688f8b3 --- /dev/null +++ b/mingw/fnmatch.h @@ -0,0 +1,299 @@ +#ifndef _FNMATCH_H_ +#define _FNMATCH_H_ + +/* + * NOTE: the below is based on https://github.com/appPlant/mruby-file-fnmatch/ + * modified by AS-2019-04-04 to fit into ATS2 libats + */ + +/* MIT License + * + * Copyright (c) 2018 Sebastian Katzer, appPlant GmbH + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#define FNM_NOESCAPE 0x01 +#define FNM_PATHNAME 0x02 +#define FNM_DOTMATCH 0x04 +#define FNM_CASEFOLD 0x08 +#define FNM_EXTGLOB 0x10 +#define FNM_NOMATCH 1 + +#include +#include +#include +#include + +/* + * Copy string src to buffer dst of size dsize. At most dsize-1 + * chars will be copied. Always NUL terminates (unless dsize == 0). + * Returns strlen(src); if retval >= dsize, truncation occurred. + */ +static size_t +_strlcpy_(char *dst, const char *src, size_t dsize) +{ + const char *osrc = src; + size_t nleft = dsize; + + /* Copy as many bytes as will fit. */ + if (nleft != 0) { + while (--nleft != 0) { + if ((*dst++ = *src++) == '\0') + break; + } + } + + /* Not enough room in dst, add NUL and traverse rest of src. */ + if (nleft == 0) { + if (dsize != 0) + *dst = '\0'; /* NUL-terminate dst */ + while (*src++) + ; + } + + return(src - osrc - 1); /* count does not include NUL */ +} + +#define downcase(c) (nocase && isupper(c) ? tolower(c) : (c)) +#define compare(c1, c2) (((unsigned char)(c1)) - ((unsigned char)(c2))) +#define Next(p) ((p) + 1) +#define Inc(p) (++(p)) +#define Compare(p1, p2) (compare(downcase(*(p1)), downcase(*(p2)))) + +static char * +bracket(const char* p, const char* s, int flags) +{ + const int nocase = flags & FNM_CASEFOLD; + const int escape = !(flags & FNM_NOESCAPE); + + int ok = 0, nope = 0; + + if (*p == '!' || *p == '^') { + nope = 1; + p++; + } + + while (*p != ']') { + const char *t1 = p; + if (escape && *t1 == '\\') t1++; + if (!*t1) return NULL; + + p = Next(t1); + if (p[0] == '-' && p[1] != ']') { + const char *t2 = p + 1; + if (escape && *t2 == '\\') t2++; + if (!*t2) return NULL; + + p = Next(t2); + if (!ok && Compare(t1, s) <= 0 && Compare(s, t2) <= 0) ok = 1; + } else { + if (!ok && Compare(t1, s) == 0) ok = 1; + } + } + + return ok == nope ? NULL : (char *)p + 1; +} + +#define UNESCAPE(p) (escape && *(p) == '\\' ? (p) + 1 : (p)) +#define ISEND(p) (!*(p) || (pathname && *(p) == '/')) +#define RETURN(val) return *pcur = p, *scur = s, (val); + +static int +fnmatch_helper(const char** pcur, const char** scur, int flags) +{ + const int period = !(flags & FNM_DOTMATCH); + const int pathname = flags & FNM_PATHNAME; + const int escape = !(flags & FNM_NOESCAPE); + const int nocase = flags & FNM_CASEFOLD; + + const char *ptmp = 0; + const char *stmp = 0; + + const char *p = *pcur; + const char *s = *scur; + + if (period && *s == '.' && *UNESCAPE(p) != '.') /* leading period */ + RETURN(FNM_NOMATCH); + + while (1) { + switch (*p) { + case '*': + do { p++; } while (*p == '*'); + if (ISEND(UNESCAPE(p))) { + p = UNESCAPE(p); + RETURN(0); + } + if (ISEND(s)) RETURN(FNM_NOMATCH); + + ptmp = p; + stmp = s; + continue; + + case '?': + if (ISEND(s)) RETURN(FNM_NOMATCH); + p++; + Inc(s); + continue; + + case '[': { + const char *t; + if (ISEND(s)) RETURN(FNM_NOMATCH); + if ((t = bracket(p + 1, s, flags)) != 0) { + p = t; + Inc(s); + continue; + } + goto failed; + } + } + + /* ordinary */ + p = UNESCAPE(p); + if (ISEND(s)) RETURN(ISEND(p) ? 0 : FNM_NOMATCH); + if (ISEND(p)) goto failed; + if (Compare(p, s) != 0) goto failed; + + Inc(p); + Inc(s); + continue; + + failed: /* try next '*' position */ + if(ptmp && stmp) { + p = ptmp; + Inc(stmp); /* !ISEND(*stmp) */ + s = stmp; + continue; + } + RETURN(FNM_NOMATCH); + } +} + +#undef UNESCAPE +#undef ISEND +#undef RETURN + +static +int +fnmatch(const char* p, const char* s, int flags) +{ + const int period = !(flags & FNM_DOTMATCH); + const int pathname = flags & FNM_PATHNAME; + + const char *ptmp = 0; + const char *stmp = 0; + + if (pathname) { + while (1) { + if (p[0] == '*' && p[1] == '*' && p[2] == '/') { + do { p += 3; } while (p[0] == '*' && p[1] == '*' && p[2] == '/'); + ptmp = p; + stmp = s; + } + if (fnmatch_helper(&p, &s, flags) == 0) { + while (*s && *s != '/') Inc(s); + if (*p && *s) { + p++; + s++; + continue; + } + if (!*p && !*s) + return 0; + } + /* failed : try next recursion */ + if (ptmp && stmp && !(period && *stmp == '.')) { + while (*stmp && *stmp != '/') Inc(stmp); + if (*stmp) { + p = ptmp; + stmp++; + s = stmp; + continue; + } + } + return FNM_NOMATCH; + } + } else { + return fnmatch_helper(&p, &s, flags); + } +} + +static +int +fnmatch_ex(const char* p, const char* path, int flags) +{ + const int escape = !(flags & FNM_NOESCAPE); + const char *s = p; + const char *lbrace = 0, *rbrace = 0; + int nest = 0, status = 0; + + while (*p) { + if (*p == '{' && nest++ == 0) { + lbrace = p; + } + if (*p == '}' && lbrace && --nest == 0) { + rbrace = p; + break; + } + if (*p == '\\' && escape) { + if (!*++p) break; + } + Inc(p); + } + + if (lbrace && rbrace) { + size_t len = strlen(s) + 1; + char *buf = malloc(sizeof(char) * len); + long shift; + + if (!buf) return -1; + memcpy(buf, s, lbrace-s); + shift = (lbrace-s); + p = lbrace; + while (p < rbrace) { + const char *t = ++p; + nest = 0; + while (p < rbrace && !(*p == ',' && nest == 0)) { + if (*p == '{') nest++; + if (*p == '}') nest--; + if (*p == '\\' && escape) { + if (++p == rbrace) break; + } + Inc(p); + } + memcpy(buf+shift, t, p-t); + _strlcpy_(buf+shift+(p-t), rbrace+1, len-(shift+(p-t))); + status = fnmatch(buf, path, flags) == 0; + if (status) break; + } + + free(buf); + } + else if (!lbrace && !rbrace) { + status = fnmatch(s, path, flags) == 0; + } + + return status; +} + +#undef downcase +#undef compare +#undef Next +#undef Inc +#undef Compare + +#endif /* _FNMATCH_H_ */