commit bdfc7e4abaca7fb8583f858d12435d98169e5a74
parent 8efda46ed9f5507e91712ea977e3ea79697349a4
Author: Evgeny Grin <k2k@drgrin.dev>
Date: Fri, 2 May 2025 19:56:09 +0300
demo.c: fully ported to MSVC
Diffstat:
| M | src/examples2/demo.c | | | 207 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------- |
1 file changed, 179 insertions(+), 28 deletions(-)
diff --git a/src/examples2/demo.c b/src/examples2/demo.c
@@ -30,24 +30,56 @@
* @author Karlson2k (Evgeny Grin)
*/
#include <microhttpd2.h>
-#include <unistd.h>
+#include <sys/types.h>
+#include <stdbool.h>
+#if ! defined(_WIN32) || defined(__CYGWIN__)
+# include <unistd.h>
+#else
+# include <direct.h>
+#endif
#include <stdio.h>
#include <stdlib.h>
-#include <stdbool.h>
#include <signal.h>
#include <fcntl.h>
#include <sys/stat.h>
-#include <pthread.h>
#include <string.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <dirent.h>
+#if ! defined(_WIN32) || defined(__CYGWIN__)
+# include <dirent.h>
+#else
+# include <io.h>
+#endif
#ifdef MHD_HAVE_LIBMAGIC
-#include <magic.h>
+# include <magic.h>
#endif /* MHD_HAVE_LIBMAGIC */
#include <limits.h>
#include <ctype.h>
#include <errno.h>
+#if defined(_WIN32) && ! defined(__CYGWIN__)
+# include <locale.h>
+#endif
+
+#if ! defined(_WIN32) || defined(__CYGWIN__)
+# include <pthread.h>
+typedef pthread_mutex_t my_mutex_t;
+# define my_mutex_init(pmtx) ((void) pthread_mutex_init ((pmtx), NULL))
+# define my_mutex_destroy(pmtx) ((void) pthread_mutex_destroy ((pmtx)))
+# define my_mutex_lock(pmtx) ((void) pthread_mutex_lock ((pmtx)))
+# define my_mutex_unlock(pmtx) ((void) pthread_mutex_unlock ((pmtx)))
+#else
+# define WIN32_LEAN_AND_MEAN 1
+# include <windows.h>
+typedef CRITICAL_SECTION my_mutex_t;
+# define my_mutex_init(pmtx) ((void) InitializeCriticalSection ((pmtx)))
+# define my_mutex_destroy(pmtx) DeleteCriticalSection ((pmtx))
+# define my_mutex_lock(pmtx) EnterCriticalSection ((pmtx))
+# define my_mutex_unlock(pmtx) LeaveCriticalSection ((pmtx))
+#endif
+
+#ifdef S_ISREG
+# define my_S_ISREG(arg) S_ISREG (arg)
+#else
+# define my_S_ISREG(arg) (_S_IFREG == ((arg)&_S_IFMT))
+#endif
#if defined(MHD_CPU_COUNT) && (MHD_CPU_COUNT + 0) < 2
#undef MHD_CPU_COUNT
@@ -81,6 +113,56 @@
#define MAGIC_HEADER_SIZE (16 * 1024)
#endif /* MHD_HAVE_LIBMAGIC */
+#if defined(_MSC_VER) && _MSC_VER < 1900 /* Before VS 2015 */
+/* _snprintf works differently, but the code handles it correctly */
+# define snprintf _snprintf
+#endif
+
+#if ! defined(_WIN32) || defined(__CYGWIN__)
+# define my_mkstemp(tmpl) mkstemp ((tmpl))
+#else
+static int
+my_mkstemp (char *template)
+{
+ int i;
+
+ for (i = 0; i < 32; ++i)
+ {
+ char tmp_file_name[PATH_MAX + 1];
+ HANDLE hndl;
+ if (0 == GetTempFileNameA (".",
+ template,
+ 0,
+ tmp_file_name))
+ return -1;
+ hndl = CreateFileA (tmp_file_name,
+ GENERIC_READ | GENERIC_WRITE,
+ 0,
+ NULL,
+ CREATE_ALWAYS,
+ FILE_FLAG_SEQUENTIAL_SCAN,
+ NULL);
+ if (INVALID_HANDLE_VALUE != hndl)
+ {
+ int fd;
+ fd = _open_osfhandle ((intptr_t) hndl,
+ _O_RDWR | _O_BINARY);
+ if (-1 != fd)
+ {
+ strcpy (template, tmp_file_name);
+ return fd; /* Success */
+ }
+
+ /* Failure */
+ CloseHandle (hndl);
+ }
+ (void) DeleteFileA (tmp_file_name);
+ }
+ return -1;
+}
+
+
+#endif
#ifdef HAVE_STRDUP
# define my_strdup(str) strdup ((str))
@@ -225,7 +307,7 @@ static struct MHD_Response *request_refused_response;
/**
* Mutex used when we update the cached directory response object.
*/
-static pthread_mutex_t mutex;
+static my_mutex_t mutex;
#ifdef MHD_HAVE_LIBMAGIC
/**
@@ -268,11 +350,11 @@ update_cached_response (struct MHD_Response *response)
MHD_YES)))
exit (1);
}
- (void) pthread_mutex_lock (&mutex);
+ my_mutex_lock (&mutex);
if (NULL != cached_directory_response)
MHD_response_destroy (cached_directory_response);
cached_directory_response = response;
- (void) pthread_mutex_unlock (&mutex);
+ my_mutex_unlock (&mutex);
}
@@ -310,6 +392,7 @@ static bool
list_directory (struct ResponseDataContext *rdc,
const char *dirname)
{
+#if ! defined(_WIN32) || defined(__CYGWIN__)
char fullname[PATH_MAX + 1];
struct stat sbuf;
DIR *dir;
@@ -335,7 +418,8 @@ list_directory (struct ResponseDataContext *rdc,
{
void *r;
- if ( (2 * rdc->buf_size + 1024) < rdc->buf_size)
+ if ((2 * rdc->buf_size < rdc->buf_size) ||
+ (2 * rdc->buf_size + 1024) < rdc->buf_size)
break; /* more than SIZE_T _index_ size? Too big for us */
rdc->buf_size = 2 * rdc->buf_size + 1024;
if (NULL == (r = realloc (rdc->buf, rdc->buf_size)))
@@ -354,6 +438,53 @@ list_directory (struct ResponseDataContext *rdc,
rdc->off += (size_t) res;
}
(void) closedir (dir);
+#else
+ char search_patt[PATH_MAX + 1];
+ struct _finddatai64_t finfo;
+ intptr_t dir;
+ if (sizeof(search_patt) <=
+ (size_t) snprintf (search_patt,
+ sizeof(search_patt),
+ "%s\\*",
+ dirname))
+ return false;
+ if (-1 == (dir = _findfirsti64 (search_patt,
+ &finfo)))
+ return false;
+ do
+ {
+ int res;
+
+ if (0 != (finfo.attrib & (_A_HIDDEN | _A_SUBDIR | _A_SYSTEM)))
+ continue; /* Not a regular file, skip */
+ if (rdc->off + 1024 > rdc->buf_size)
+ {
+ void *r;
+
+ if ((2 * rdc->buf_size < rdc->buf_size) ||
+ (2 * rdc->buf_size + 1024) < rdc->buf_size)
+ break; /* more than SIZE_T _index_ size? Too big for us */
+ rdc->buf_size = 2 * rdc->buf_size + 1024;
+ if (NULL == (r = realloc (rdc->buf, rdc->buf_size)))
+ break; /* out of memory */
+ rdc->buf = (char *) r;
+ }
+ res = snprintf (rdc->buf + rdc->off,
+ rdc->buf_size - rdc->off,
+ "<li><a href=\"/%s/%s\">%s</a></li>\n",
+ dirname,
+ finfo.name,
+ finfo.name);
+ if (0 >= res)
+ continue; /* snprintf() error */
+ if (rdc->buf_size - rdc->off <= (size_t) res)
+ continue; /* buffer too small?? */
+ rdc->off += (size_t) res;
+
+ } while (0 == _findnexti64 (dir,
+ &finfo));
+ (void) _findclose (dir);
+#endif
return true;
}
@@ -619,7 +750,7 @@ stream_reader (struct MHD_Request *req,
if (! isprint ((unsigned char) uc->filename[i]))
uc->filename[i] = '_';
}
- uc->fd = mkstemp (uc->tmpname);
+ uc->fd = my_mkstemp (uc->tmpname);
if (-1 == uc->fd)
{
fprintf (stderr,
@@ -703,7 +834,7 @@ handle_full_upload (void *cls,
return MHD_NO;
}
uc->filename = my_strdup (data->filename.cstr);
- fd = mkstemp (uc->tmpname);
+ fd = my_mkstemp (uc->tmpname);
if (-1 == fd)
{
fprintf (stderr,
@@ -873,18 +1004,20 @@ done_cb (struct MHD_Request *req,
request_refused_response);
goto cleanup;
}
+#if ! defined(_WIN32) || defined(__CYGWIN__)
chmod (uc->filename,
S_IRUSR | S_IWUSR);
+#endif
update_directory ();
- (void) pthread_mutex_lock (&mutex);
+ my_mutex_lock (&mutex);
if (NULL == cached_directory_response)
ret = MHD_upload_action_from_response (req,
internal_error_response);
else
ret = MHD_upload_action_from_response (req,
cached_directory_response);
- (void) pthread_mutex_unlock (&mutex);
+ my_mutex_unlock (&mutex);
cleanup:
if (NULL != uc->filename)
free (uc->filename);
@@ -911,8 +1044,8 @@ cleanup:
* socket closure). */
static const struct MHD_Action *
generate_page (void *cls,
- struct MHD_Request *request,
- const struct MHD_String *path,
+ struct MHD_Request *MHD_RESTRICT request,
+ const struct MHD_String *MHD_RESTRICT path,
enum MHD_HTTP_Method method,
uint_fast64_t upload_size)
{
@@ -951,14 +1084,18 @@ generate_page (void *cls,
"..")) &&
(0 != url[0]) &&
(0 != url[1]) &&
- ('/' != url[1]) )
- {
- fd = open (&url[1],
+#ifdef _WIN32
+ ('\\' != url[1]) &&
+ ((3 > path->len) || ':' != url[2]) &&
+#endif
+ ('/' != url[1]) )
+ fd = open (url + 1,
O_RDONLY);
- if ( (-1 != fd) &&
- ( (0 != fstat (fd,
- &buf)) ||
- (! S_ISREG (buf.st_mode)) ) )
+ if (-1 != fd)
+ {
+ if ((0 != fstat (fd,
+ &buf))
+ || ! my_S_ISREG (buf.st_mode))
{
(void) close (fd);
fd = -1;
@@ -1059,14 +1196,14 @@ generate_page (void *cls,
{
const struct MHD_Action *ret;
- (void) pthread_mutex_lock (&mutex);
+ my_mutex_lock (&mutex);
if (NULL == cached_directory_response)
ret = MHD_action_from_response (request,
internal_error_response);
else
ret = MHD_action_from_response (request,
cached_directory_response);
- (void) pthread_mutex_unlock (&mutex);
+ my_mutex_unlock (&mutex);
return ret;
}
/* unexpected request, refuse */
@@ -1115,6 +1252,17 @@ ignore_sigpipe (void)
#endif
+#if defined(_WIN32) && ! defined(__CYGWIN__)
+static void
+set_utf8_locale (void)
+{
+ if (NULL != setlocale (LC_CTYPE, ".UTF8"))
+ return; /* Success */
+ (void) setlocale (LC_CTYPE, "C"); /* A fallback, not really helpful */
+}
+
+
+#endif
/**
* Entry point to demo. Note: this HTTP server will make all
@@ -1146,12 +1294,15 @@ main (int argc,
#if ! defined(_WIN32) || defined(__CYGWIN__)
ignore_sigpipe ();
#endif
+#if defined(_WIN32) && ! defined(__CYGWIN__)
+ set_utf8_locale ();
+#endif
#ifdef MHD_HAVE_LIBMAGIC
magic = magic_open (MAGIC_MIME_TYPE);
(void) magic_load (magic, NULL);
#endif /* MHD_HAVE_LIBMAGIC */
- (void) pthread_mutex_init (&mutex, NULL);
+ my_mutex_init (&mutex);
file_not_found_response =
MHD_response_from_buffer_static (
MHD_HTTP_STATUS_NOT_FOUND,
@@ -1219,7 +1370,7 @@ main (int argc,
MHD_response_destroy (request_refused_response);
MHD_response_destroy (internal_error_response);
update_cached_response (NULL);
- (void) pthread_mutex_destroy (&mutex);
+ my_mutex_destroy (&mutex);
#ifdef MHD_HAVE_LIBMAGIC
magic_close (magic);
#endif /* MHD_HAVE_LIBMAGIC */