Introduction
The main purpose for these C functions is to display notifications for applications in different environments (CGI, Console, GUI, Log).
The functions should be portable between environments and platforms.
Unless using an explicit call, the environment should be automatically detected.
Thus, calling for example the frontend function
np_info("Hello, world!\n");
would automatically choose one of the following backend functions, depending on the detected environment and platform:
- CGI: Create a
<p>INFO: Hello, world!</p>
HTML block - Console: Call
printf("INFO: Hello, world!\n")
- GUI (Win32): Call
MessageBox(NULL, "INFO: Hello, world!", "Hello, world!\n", MB_OK)
- GUI (Linux/BSD): Call
zenity()
,kdialog()
, orxmessage()
with"Hello, world!\n"
as input (and setting the INFO icon where applicable) - Log (only if no environment could be detected): Print to log file:
fprintf(LOGFILE, "INFO: Hello, world!\n")
All frontend functions use the printf(3)
function format string syntax.
Special use case in mind: file name arguments
These C functions are generic in nature, but have been designed with a special case in mind:
When starting an application and passing file names as arguments, display whatever notification during the verification of the file names.
Usage examples:
- An info message which just lists all the (file name) arguments.
- A warning message if a file may cause a problem.
- An error message if one or more files does not fulfill a mandatory condition
(unsupported file extension, empty or non-existing file, etc.).
- A confirm message if a file in the list may overwrite an existing file.
Passing file name arguments in different environments
The file name arguments may be passed to the application in different ways:
- CGI: Drag files from a Desktop environment and drop them over a web page, display a HTML block in the web page
- Console: Type command-line arguments, display a text message
- GUI: Drag/drop files over an application in a Desktop environment, display a popup window
- Log: N/A
Platform dependent environment detection
To decide which backend function to call for output, the environment must first be detected.
This may vary between platforms. These are the following steps for environment detection:
The CGI environment is probably the easiest environment to detect, as it is platform independent.
Usually it is sufficient to check a set of environment variables to be present, and another set which should be absent.A Console environment may be more complicated to detect, as a console application may run in different environments:
- In a text-only environment (may be true for for a Linux/BSD system not running an X server).
- As a console window in a GUI environment (always true for MS Windows, may be true for Linux/BSD)
Besides, the method for detecting a console window is different for the type of console:- MS Windows, CMD Command Prompt:
cmd.exe
- MS Windows, MSYS2/MINGW64/Cygwin console:
mintty
- Linux/BSD:
xterm
etc. (normally one single detection method can be used for all kind of Linux/BSD consoles)
- MS Windows, CMD Command Prompt:
A GUI environment is easy to detect when a console environment has been discharged.
Additional detection methods may include reading the PE header (MS Windows) or the$DISPLAY
environment variable (Linux/BSD).
The backend funtion is platform dependent:- MS Windows:
MessageBox()
- Linux/BSD:
zenity
,kdialog
, orxmessage
(whatever that is detected at run-time)
- MS Windows:
A Log "environment" is not a real environment in this context. It is only used if the detection of the other environments fails.
Platform dependent input/output
Once the environment has been detected, the proper backend function for notification has to be called. This may be also platform dependent.
Generally, Console and CGI input/output functions are platform independent.
For example, printf()
and scanf()
are included in every C library, and can be used for printing to/reading from directly using any console input/output.
Creating HTML blocks in CGI applications is also a platform independent call.
Note that scanf()
is only used for console confirm messages.
On the other hand, GUI input/output functions are platform dependent.
The MsgBox()
function is very MS Windows specific, and xmessage
is normally only available on Linux/BSD systems.
Printing to a Log file is platform independent, using fprintf(LOGFILE, ...)
on any platform.
Split source code files by platform
Not everyone are interested in using code for all platforms.
The source code has been designed with the idea that it should be easy to grab the source code files for one single platform, so code blocks such as
<common source code>
#if defined (__linux__)...
<Linux-specific source code>
#elif defined (_WIN32)...
<MS Windows-specific source code>
#endif
<more common source code>
have been avoided as much as possible.
The compile time OS-related directive have instead been included outside the source code, at a higher level, in the Makefile and in common headers.
Compile time OS-related directives here:
Win32 platform notes
Win32 application compiling
On MS Windows, 3 different ways to compile an application have been tested.
Depending on the compiler, the resulting application may have a DLL dependency or not:
- MINGW64 shell - No DLL dependency
- MSYS2 shell - DLL dependency:
msys-2.0.dll
- Cygwin shell - DLL dependency:
cygwin1.dll
Win32 application launching
On MS Windows, 5 different ways to launch an application have been tested:
- MINGW64 shell
- MSYS2 shell
- Cygwin shell
- CMD prompt (
cmd.exe
) - File Explorer/GUI (double-click to launch)
Generally, GUI applications may be launched using any of the 5 ways.
Console applications may be launched using any console application (1-4) except File Explorer.
(Note that console applications are not limited to text-only output, but may also create GUI windows.)
Anyhow, due to DLL dependencies, applications compiled using the MSYS2 shell may only be launched from either a MSYS2 or a MINGW64 shell.
The same is true for applications compiled using the Cygwin shell, which may only be launched from a Cygwin shell.
To launch an application using any of the 5 ways, always compile it using the MINGW64 shell.
Win32 environment detection
It is important to detect the correct launching application to know whether to use printf()
or MessageBox()
as a backend function for output.
To compile an application as either a GUI or Console, the -mconsole
(default on MINGW64) or -mwindows
compiler flag is used.
When compiled as a Console program, printf()
will always work, launch from either a Console or the File Explorer.
(In this case, when launched from the File Explorer, an attached console is opened, and any printf()
output goes to that console.)
When compiled as a GUI program (i.e., using -mwindows
), the program can be perfectly launched from a console,
but printf()
output will only be visible if launched from a MINGW64/MSYS2/Cygwin console, but not from the CMD prompt.
A simple workaround for this would be to always use MessageBox()
for notifications, but there are more sophisticated methods to detect which output function to use at runtime.
Detect how a Win32 application has been compiled
Read the PE Subsystem header:
- PE Subsystem header =
IMAGE_SUBSYSTEM_WINDOWS_CUI
=> Compiled with:-mconsole
- PE Subsystem header =
IMAGE_SUBSYSTEM_WINDOWS_GUI
=> Compiled with:-mwindows
- PE Subsystem header =
Check if a GUI application has an attached console:
(GetStdHandle(STD_OUTPUT_HANDLE) != INVALID_HANDLE_VALUE) /* Attached console, compiled with -mconsole */ (GetStdHandle(STD_OUTPUT_HANDLE) == INVALID_HANDLE_VALUE) /* No attached console, compiled with -mwindows */
Check the console's Code Page:
(GetConsoleOutputCP() != 0) /* Console Code Page may vary, but always non-zero for a console => -mconsole */ (GetConsoleOutputCP() == 0) /* Console Code Page is 0 => -mconsole */
Detect how a Win32 application has been launched
Check the
PROMPT
variable:(getenv("PROMPT") != NULL) /* Launched from CMD prompt */ (getenv("PROMPT") == NULL) /* Launched from File Explorer (or from MINGW64/MSYS2/Cygwin) */
Check the
MSYSTEM
variable:(!strncmp(getenv("MSYSTEM"), "MINGW64")) /* Launched from MINGW64 shell */ (!strncmp(getenv("MSYSTEM"), "MSYS")) /* Launched from MSYS2 shell */ (getenv("MSYSTEM") == NULL) /* Launched from File Explorer, CMD prompt or Cygwin) */
The MINGW64/MSYS2/Cygwin shells use named pipes to emulate a console.
To get the name of the pipe, callNtQueryInformationFile()
, which returns a name like this:\cygwin-e022582115c10879-pty0-from-master /* Launched from Cygwin shell */ \msys-dd50a72ab4668b33-pty0-from-master /* Launched from MINGW64 or MSYS2 shell */
Use the
_isatty()
call to check if STDIN, STDOUT and/or STDERR are terminal types:((_isatty(0) || _isatty(1) || _isatty(2)) /* Launched from CMD prompt */ !((_isatty(0) || _isatty(1) || _isatty(2)) /* Launched from File Explorer or from MINGW64/MSYS2/Cygwin */
Note that it is possible to simultaneously use redirection for both STDIN, STDOUT and STDERR, as shown in the following command:
dir | ./test-if-my-app-is-a-terminal.exe > my-app.log 2>&1
In this case
((_isatty(0) || _isatty(1) || _isatty(2))
will return 0.
%%% TODO %%% Add "detected console/gui/cgi type" functions to API, not as "private functions"
TODO: REDUCE THE SECTION BELOW (BEFORE API)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Environment detection
The output format (and function used) depends on the current environment, so the environment has to be detected, in this order: TTY, GUI, or CGI.
Environment: TTY
- Detection:
if (isatty(0) || isatty(1) || isatty(2)) ...
- Output functions:
np_settings_t set = {NP_TYPE, NP_ENV_TTY, NP_X_POPUP_NONE);
int np_msg_set(np_settings_t set, const char *fmt, ...);
- Platform call:
fprintf()
- Example: When an application is running from the command line, print messages to STDOUT/STDERR.
Note 1:
Theoretically, a call to isatty(0)
would suffice to check if the current environment is a terminal or not.
In practice, things get a bit more complicated. Not surprisingly, MS Windows
Note 2: It is possible to simultaneously use redirection for both STDIN, STDOUT and STDERR, as shown in the following command:
dir | ./isatty-for-native-apps.exe > kk.txt 2>&1
In such a case, the TTY environment would not be detected, as (isatty(0) || isatty(1) || isatty(2))
returns false.
As an extra check, the $TERM
environment variable may be queried.
This works for any UNIX-like system as well as for MSYS2/MINGW64/CYGWIN terminals.
The exception is the MS Windows CMD promt, which does not recognize the %TERM%
variable.
Environment: GUI
- Detection:
if (!(isatty(0))) ...
- Output function:
np_env(NP_TYPE, NP_ENV_GUI)
- Platform call: OS dependent
- Example: When an application is running in GUI environment (Drag n Drop), show a GUI notification.
Environment: GUI: MS Windows
- Output function:
np_env_os(NP_TYPE, NP_ENV_GUI, NP_OS_WIN32|NP_OS_MSYS2|NP_OS_MINGW64)
- Platform call:
MsgBox()
(MS Windows native function)
Environment: GUI: Linux/*BSD/UNIX
- Additional detection:
if (getenv("DISPLAY")) ...
- Output function:
np_env_os_dialog(NP_TYPE, NP_ENV_GUI, NP_OS_UNIX, NP_X_POPUP)
- Platform call:
NP_X_POPUP
=zenity
/kdialog
/xmessage
(whatever is detected at runtime)
Note:
There are several different graphic environments available for Linux/*BSD/UNIX,
many of them with there own GUI dialog boxes.
To take all of them into account would imply linking np_gui_x()
to several graphic libraries.
Instead, to avoid the graphic library linking, available dialog/notifying/message programs are detected at runtime.
The output function used depends on the detected available program(s) in the following order:
np_env_os_dialog(NP_TYPE, NP_ENV_GUI, NP_OS_UNIX, NP_X_POPUP_ZENITY)
ifzenity
is detected (GNOME)np_env_os_dialog(NP_TYPE, NP_ENV_GUI, NP_OS_UNIX, NP_X_POPUP_KDIALOG)
ifkdialog
is detected (KDE)np_env_os_dialog(NP_TYPE, NP_ENV_GUI, NP_OS_UNIX, NP_X_POPUP_XMESSAGE)
ifxmessage
is detected (should be detected with any Xorg-compliant window manager)
The external program is invoked using execvp()
.
On error, the turn goes to the next program in the list.
If execvp()
fails for all external programs in the list, a log message is created instead, including an error message.
Environment: GUI: Mac OSX
- Detection: Not implemented. Is
if (!(isatty(0))) ...
enough to detect GUI on Mac? - Output function:
np_env_os(NP_TYPE, NP_ENV_GUI, NP_OS_MACOS)
- Backend:
CFUserNotificationDisplayAlert()
(Mac OS native function)
NOTE: Not implemented. Help yourself:
http://macosx-programming.blogspot.com/2011/09/message-box-using-corefoundation.html
http://macosx-programming.blogspot.com/2011/09/simplified-version-of-corefoundation.html
Cocoa implies using Object-C and should be avoided:
https://github.com/cocoadialog/cocoadialog
Environment: GUI: Smartphones
These functions were designed with Drag n Drop operations in mind, i.e. Desktop environments.
Smartphone touch screens do not use the Drag n Drop operations to drop files over an application.
Even if the notifications themselves are generic, using these functions in smartphone applications makes little or no sense.
Smartphone devices are just listed here for completeness.
Environment: GUI: Android
- Detection: Not implemented (and will probably never be implemented)
- Output function:
np_env_os(NP_TYPE, NP_ENV_GUI, NP_OS_ANDROID)
- Backend: Not implemented. Help yourself, see https://developer.android.com/ndk/samples/sample_hellojni`
TTY on Android:
Applications run in Android's Termux shell, could theoretically use np_tty()
for a notification,
but it makes probably more sense to use printf()
directly instead.
Logging on Android:
https://stackoverflow.com/questions/10274920/how-to-get-printf-messages-written-in-ndk-application
#include <android/log.h>
__android_log_print(ANDROID_LOG_DEBUG, "LOG_TAG", "\n this is a log message. \n");
Environment: GUI: iOS
- Detection: Not implemented (and will probably never be implemented)
- Output function:
np_env_os(NP_TYPE, NP_ENV_GUI, NP_OS_IOS)
- Backend: Not implemented. Help yourself, see https://developer.apple.com/documentation/uikit/uialertcontroller
Environment: CGI
- Detection:
if (getenv("SERVER_NAME")) ...
- Output function:
np_env(NP_TYPE, NP_ENV_CGI)
- Backend: HTML block
- Example: When an application is running as a CGI, show a HTML block with an info/error message.
Environment: No environment detected
- Detection: Everything else failed
- Output function:
np_env(NP_TYPE, NP_ENV_LOG)
- Backend:
fprintf(LOG, ...)
In the rare case of not detecting any environment, redirect output to a log file.
(In case of log file creation failed, output nothing.)
API
Enums
enum NP_TYPE { NP_TYPE_UNKNOWN, NP_TYPE_INFO, NP_TYPE_WARNING, NP_TYPE_ERROR, NP_TYPE_CONFIRM, NP_TYPE_MAX };
enum NP_ENV { NP_ENV_UNKNOWN, NP_ENV_AUTO, NP_ENV_TTY, NP_ENV_GUI, NP_ENV_CGI, NP_ENV_LOG, NP_ENV_MAX };
enum NP_X_POPUP { NP_X_POPUP_UNKNOWN, NP_X_POPUP_NONE, NP_X_POPUP_AUTO, NP_X_POPUP_ZENITY, NP_X_POPUP_KDIALOG, NP_X_POPUP_XMESSAGE, NP_X_POPUP_MAX };
Internal (OS variables not needed at runtime???):
enum NP_OS { NP_OS_WIN32, NP_OS_MSYS2, NP_OS_MINGW64, NP_OS_CYGWIN, NP_OS_UNIX, NP_OS_MACOS, NP_OS_ANDROID, NP_OS_IOS, NP_OS_MAX };
Typedefs
Settings for a notification.
typedef struct np_settings_t
{
enum NP_TYPE type;
enum NP_ENV env;
enum NP_X_POPUP x_popup;
} np_settings_t;
Functions
Main functions
int np_info(const char *fmt, ...);
int np_warning(const char *fmt, ...);
int np_error(const char *fmt, ...);
int np_confirm(const char *fmt, ...);
All functions returns 0 (OK
) or -1 (ERROR
).
Besides, np_confirm()
returns 0 on confirm (OK
/Yes
etc) or 1 (No
/Cancel
etc).
Usage:
np_info("Hello, world\n");
Generic functions
- int
np_msg(enum NP_TYPE np_type, const char *fmt, ...)
The functions np_info()
, np_warning()
, np_error()
, np_confirm()
are all wrappers for np_msg()
.
Usage:
Choose NP_TYPE:
enum NP_TYPE np_type = NP_TYPE_INFO|NP_TYPE_WARNING|NP_TYPE_ERROR|NP_TYPE_CONFIRM;
Call
np_msg()
:np_msg(np_type, "Hello, world!\n");
Backend function, call by all the othes above
- int
np_msg_set(np_settings_t set, const char *fmt, ...)
Instead of auto-detection, force specific settings, such as environment and/or X Windows popup dialog .
Usage:
Set
NP_TYPE
,NP_ENV
,NP_X_POPUP
:enum NP_TYPE np_type = NP_TYPE_INFO|NP_TYPE_WARNING|NP_TYPE_ERROR|NP_TYPE_CONFIRM; enum NP_ENV np_env = NP_ENV_AUTO|NP_ENV_TTY|NP_ENV_GUI|NP_ENV_CGI|NP_ENV_LOG: enum NP_X_POPUP np_x_popup = NP_X_POPUP_AUTO|NP_X_POPUP_ZENITY|NP_X_POPUP_KDIALOG|NP_X_POPUP_XMESSAGE|
Settings:
np_settings_t np_set = {np_type, np_env, np_x_popup);
Call
np_msg_set()
:np_msg_set(np_set, "Hello, world!\n");
For example, these three calls are equivalent:
np_info("Hello, world!\n");
np_msg(NP_TYPE_INFO, "Hello, world!\n");
np_settings_t set = {NP_TYPE_INFO, NP_ENV_AUTO, NP_X_POPUP_AUTO}; np_msg_set(np_set, "Hello, world!\n");
Example:
Force using a GUI popup instead of STDOUT, even if a program is run from a terminal:
`np_settings_t np_set = {NP_TYPE_INFO, NP_ENV_GUI, NP_X_POPUP_AUTO); np_msg_set(np_set, "Hello, world!\n");`
Example:
Force using a log message, even if a program is run from a GUI or a terminal:
`np_settings_t np_set = {NP_TYPE_INFO, NP_ENV_GUI, NP_X_POPUP_NONE); np_msg_set(np_set, "Hello, world!\n");`
NOTE:
Certain combinations for np_settings_t
are invalid:
- Setting
np_env
toNP_ENV_GUI
orNP_ENV_CGI
in a text-only environment is invalid and will obviously fail. - Setting
np_x_popup
to any other value thanNP_X_POPUP_NONE
in a non-X-Windows environment is invalid. - Setting
np_env
toNP_ENV_LOG
and callnp_confirm()
(interactive, requires input) is invalid.
In such invalid cases, the message will be displayed on STDOUT, together with a warning message on STDERR, or logged to a file, if STDOUT/STDERR are not available.
Demo application: Test TTY/GUI/CGI output
The demo application np-demo
/np-demo.exe
tests all kind of notifications, and is expected to have the following behaviour:
- TTY:
- Open a terminal (xterm/MSYS2/MINGW64/Termux) or login in text mode (Linux/*BSD/UNIX only).
- Run
np-demo[.exe] file1 file2 file3 ...
The filenames should be printed on STDOUT. - Run
np-demo[.exe] file1 file2 file3.np-error ...
The*.np-error
filename(s) should be printed on STDERR. - Run
np-demo[.exe] file1 file2 file3.np-none ...
The*.np-none
filenames should be logged tonp-demo.log
, but no message to either STDOUT nor STDERR.
- GUI:
- In a file manager, drag one or more files over the demo executable. The filename(s) should be listed in a info dialog.
- Drag one or more files over the demo executable, where one or more of the files has the extension
.np-error
. The.np-error
filenames should be listed in an error dialog. - Drag one or more files over the demo executable, where one or more of the files has the extension
.np-none
. The*.np-none
filenames should be logged tonp-demo.log
, but no dialog should be shown.
- CGI:
- Run as CGI application.
- Upload
np-demo
/np-demo.exe
to a web server's which has CGI-enabled directory, such ascgi-bin/
.
(Be sure that the application has been compiled for the same OS as the web server.)
Point a browser to the URL http://WEB-SERVER/cgi-bin/np-demo. - As an alternative, running
np-demo
/np-demo.exe
without any arguments, starts a local web server on 127.0.0.1, port 8080.
Run from a terminal without any arguments starts the web server.
To do the same from a GUI, just double-clicknp-demo
/np-demo.exe
.
The server is started, and http://127.0.0.1:8080/np-demo opens in a web browser.
In this case, there are two instances running ofnp-demo
/np-demo.exe
, one as a server, and one as a CGI script.
Detecting that this is anp-demo
web server, an extra "power off" button is added to the web page, which permits to shut down the server from the browser.
- Upload
- From a file manager, drag one or more files over the web page.
The filename(s) should be listed in an HTML info dialog on the web page. - From a file manager, drag one or more files over the web page, where one or more of the files has the extension
.np-error
.
The*.np-error
filename(s) should be listed in an HTML error dialog on the web page. - From a file manager, drag one or more files over the web page, where one or more of the files has the extension
.np-none
.
The*.np-none
filenames should be logged tonp-demo.log
, but no dialog should be shown.
- Run as CGI application.
MSYS2 notes:
Note that if the demo executable has been compiled in MSYS2 environment, np-demo.exe
cannot be run by double-clicking the icon in MS Windows' File Explorer.
CGI-enabled web servers for TTY/GUI/CGI demo application
See also webservers-cgi project.
The demo application requires an embedded CGI-enabled HTTP server.
The embedded web server:
- should be minimal
- should have support for HTTP
- should have support for CGI (C is mandatory, Perl is nice-to-have)
- should NOT support any other functionality, such as:
- SSI
- HTTPS
- websockets
- directory listing
- authentication
- redirection
- threads
- etc
Besides containing an embedded web server, the demo application itself may act as any CGI application. If installed in a CGI-enabled directory for another web server, that web server may run the demo application instead, as in this case, the embedded web server is not started.
Starting the demos app should also launch a browser with the URL, such as
fossil ui
or
mongoose-free-6.9.exe
-start_browser yes (default)
To make the demo application as portable as possible between OS:es, both POSIX sockets and Winsock sockets should be supported.
If HTTP-CGI server compiles both with MSYS2 (POSIX) and with Mingw64 (Winsock), chances are (big) that the web server works for several other OS:es as well.
Note: The resulting executable on MS Windows should always be compiled with Mingw64, not with MSYS2, to avoid the msys-2.0.dll dependency. Executables linked with msys-2.0.dll do not work when running from the MS Windows Shell (File Explorer).
CGI-enabled web server: MinGW64: Civetweb
See also webservers-cgi project.
https://github.com/civetweb/civetweb
MinGW64:
wget https://github.com/civetweb/civetweb/archive/master.zip -O civetweb-master.zip
unzip civetweb-master.zip
cd civetweb-master
mingw32-make CC=gcc
mingw32-make
./civetweb.exe
cp ../cgi-bin/hellohtml.exe .
cp ../cgi-bin/hellohtml.exe hellohtml.cgi
./civetweb.exe -listening_ports 1236 -cgi_pattern '**.exe$|**.cgi'
http://127.0.0.1:1236/hellohtml.exe
http://127.0.0.1:1236/hellohtml.cgi
- Pros: Works for MinGW64, notifications, integrates nice with Windows systray, CGI works for C applications with both .exe and .cgi extensions
Cons: CGI works for either C programs or Perl scripts, but not both of them simultaneously:
Error 500: Internal Server Error Error: Cannot spawn CGI process [C:\fossil\nested\notify-portable\civetweb-master/hellohtml-perl.cgi]: No such file or directory
Workaround for Perl scripts (NOTE: makes C programs stop working as CGI): cgi_interpreter
https://github.com/cztomczak/phpdesktop/issues/68
./civetweb.exe -listening_ports 1236 -cgi_pattern '**.exe$|**.cgi|**.pl' -cgi_interpreter '\\usr\\bin\\perl.exe' <-- ERROR
./civetweb.exe -listening_ports 1236 -cgi_pattern '**.exe$|**.cgi|**.pl' -cgi_interpreter '\\c\\msys64\\usr\\bin\\perl.exe' <-- ERROR
./civetweb.exe -listening_ports 1236 -cgi_pattern '**.exe$|**.cgi|**.pl' -cgi_interpreter 'C:\\msys64\\usr\\bin\\perl.exe' <-- OK (for Perl scripts, but not for C)
CGI-enabled web server: MSYS2: Merecat
See also webservers-cgi project.
Merecat works with MSYS2:
wget https://github.com/troglobit/merecat/archive/master.zip -O merecat-master.zip
unzip merecat-master.zip
cd merecat-master
./autogen.sh
mkdir -p build/usr build/var build/etc
./configure --prefix=$PWD/build/usr --localstatedir=$PWD/build/var --sysconfdir=$PWD/build/etc --disable-dirlisting --without-config --without-ssl --without-symlinks --without-zlib
make
make install
build/usr/sbin/merecat.exe -p 8888 -c "**.cgi|**.exe|**.pl|**/cgi-bin/*"
cp ../cgi-bin/hellohtml.exe .
http://127.0.0.1:8888/hellohtml.exe
- Pros: Works out of the box for MSYS2, works for both C and Perl CGI simultaneously.
- Cons: Does not work for MinGW64, uses autoconf/automake
Other CGI-enabled web servers
CGI-enabled web server: MinGW64: Mongoose
See also webservers-cgi project.
https://github.com/cesanta/mongoose
https://cesanta.com/docs/overview/build-options.html
https://cesanta.com/docs/http/cgi.html
https://cesanta.com/docs/http/server-example.html
https://github.com/cesanta/mongoose/tree/master/examples/simplest_web_server
CGI problems with mongoose compiled with MinGW64:
wget https://github.com/cesanta/mongoose/archive/master.zip -O mongoose-master.zip
unzip mongoose-master.zip
patch mongoose-master.patch # Fix casts and call to thread_enabled function
cd mongoose-master/examples/simplest_web_server
s_http_server_opts.enable_directory_listing = "no";
Makefile:
----------------------------------------
PROG = simplest_web_server
# MODULE_CFLAGS=-DMG_DISABLE_DAV_AUTH -DMG_ENABLE_FAKE_DAVLOCK
# MODULE_CFLAGS=-DMG_DISABLE_DAV_AUTH -DMG_ENABLE_FAKE_DAVLOCK -DMG_DISABLE_THREADS
#MODULE_CFLAGS=-DMG_DISABLE_DAV_AUTH -DMG_ENABLE_FAKE_DAVLOCK -DMG_ENABLE_THREADS=0
MODULE_CFLAGS=-DMG_DISABLE_DAV_AUTH -DMG_ENABLE_THREADS=0
MODULE_CFLAGS = \
-DMG_DISABLE_DAV_AUTH \
-DMG_ENABLE_FAKE_DAVLOCK \
-DMG_ENABLE_SSL=0 \
-DMG_ENABLE_IPV6=0 \
-DMG_ENABLE_MQTT=0 \
-DMG_ENABLE_MQTT_BROKER=0 \
-DMG_ENABLE_DNS_SERVER=0 \
-DMG_ENABLE_COAP=0 \
-DMG_ENABLE_HTTP=1 \
-DMG_ENABLE_HTTP_CGI=1 \
-DMG_ENABLE_HTTP_SSI=0 \
-DMG_ENABLE_HTTP_SSI_EXEC=0 \
-DMG_ENABLE_HTTP_WEBDAV=0 \
-DMG_ENABLE_HTTP_WEBSOCKET=0 \
-DMG_ENABLE_BROADCAST=0 \
-DMG_ENABLE_GETADDRINFO=0 \
-DMG_ENABLE_THREADS=0 \
-DMG_DISABLE_HTTP_DIGEST_AUTH=1 \
-DCS_DISABLE_SHA1=1 \
-DCS_DISABLE_MD5=1 \
-DMG_DISABLE_HTTP_KEEP_ALIVE=1
include ../examples.mk
----------------------------------------
./simplest_web_server.exe
cp ../../../cgi-bin/hellohtml.exe .
http://127.0.0.1:8000/hellohtml.exe
- Pros: Works (after patch) for MinGW64
- Cons: Big source code tree, does not work for MSYS2:
Starting web server on port 8000, Failed to create listener
thttpd
Tiny web server.
http://www.acme.com/software/thttpd/
- Pros: Tiny
- Cons: Does not compile, neither on MSYS2 nor MinGW64
MSYS2/MinGW64:
wget http://www.acme.com/software/thttpd/thttpd-2.29.tar.gz
tar xvfz thttpd-2.29.tar.gz
cd thttpd-2.29
./configure --host=win32 --prefix=$PWD/build
make <--- ERROR
make install
shttpd
Tiny web server.
https://docs.huihoo.com/shttpd/ https://sourceforge.net/projects/shttpd/files/shttpd/
tar xvfz shttpd-1.42.tar.gz
cd shttpd-1.42
cd src
make unix DNO_SSL=1 DNO_AUTH=1 DNO_SSI=1 DNO_THREADS=1
./shttpd.exe -ports 8889 -cgi_ext "exe,cgi,pl,php"
cp ../../cgi-bin/hellohtml.exe .
http://127.0.0.1:8889/hellohtml.exe
- Pros: Small, compiles on MSYS, easy to reduce code using flags to
make
- Cons: Does not compile on MinGW64. Compiles on MSYS2, but .exe files returns error 500.
CGI-enabled web server for both MinGW64/Win32 and MSYS2/POSIX: Merge Civetweb and Merecat code into one single server
See also webservers-cgi project.
%%% TODO MERGE!