Files
hyung-hwan d36d1a8675
continuous-integration/drone/push Build is passing
tweaked code for win32
2026-05-23 13:11:26 +09:00

537 lines
14 KiB
C

/*
* $Id$
*
Copyright (c) 2006-2020 Chung, Hyung-Hwan. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "main.h"
#include <hawk.h>
#include <hawk-fmt.h>
#include <hawk-glob.h>
#include <hawk-po.h>
#include <hawk-xma.h>
#include <stdio.h>
#include <locale.h>
#include <string.h>
#include <stdlib.h>
#if defined(_WIN32)
# include <windows.h>
# include <signal.h>
#elif defined(__OS2__)
# define INCL_ERRORS
# include <os2.h>
# include <signal.h>
#elif defined(__DOS__)
# include <dos.h>
# include <signal.h>
#else
# include <unistd.h>
# include <errno.h>
# include <signal.h>
#endif
#if !defined(LANGDIR)
#define LANGDIR "/usr/share/hawk/lang"
#endif
#if !defined(HOMELANGDIR)
#define HOMELANGDIR "/.local/share/hawk/lang"
#endif
/* ---------------------------------------------------------------------- */
hawk_pocat_t* main_pocat = HAWK_NULL;
static hawk_gem_t main_pocat_gem;
/* ---------------------------------------------------------------------- */
typedef struct sig_state_t sig_state_t;
struct sig_state_t
{
hawk_uintptr_t handler;
hawk_uintptr_t old_handler;
#if defined(HAVE_SIGACTION)
sigset_t old_sa_mask;
int old_sa_flags;
#endif
};
static sig_state_t g_sig_state[HAWK_NSIG];
static int is_signal_handler_set (int sig)
{
if (sig < 0 || sig >= HAWK_COUNTOF(g_sig_state)) return 0;
return !!g_sig_state[sig].handler;
}
#if defined(HAVE_SIGACTION)
static void dispatch_siginfo (int sig, siginfo_t* si, void* ctx)
{
if (g_sig_state[sig].handler != (hawk_uintptr_t)SIG_IGN &&
g_sig_state[sig].handler != (hawk_uintptr_t)SIG_DFL)
{
((hawk_main_sig_handler_t)g_sig_state[sig].handler) (sig);
}
if (g_sig_state[sig].old_handler &&
g_sig_state[sig].old_handler != (hawk_uintptr_t)SIG_IGN &&
g_sig_state[sig].old_handler != (hawk_uintptr_t)SIG_DFL)
{
((void(*)(int, siginfo_t*, void*))g_sig_state[sig].old_handler) (sig, si, ctx);
}
}
#endif
static void dispatch_signal (int sig)
{
if (g_sig_state[sig].handler != (hawk_uintptr_t)SIG_IGN &&
g_sig_state[sig].handler != (hawk_uintptr_t)SIG_DFL)
{
((hawk_main_sig_handler_t)g_sig_state[sig].handler) (sig);
}
if (g_sig_state[sig].old_handler &&
g_sig_state[sig].old_handler != (hawk_uintptr_t)SIG_IGN &&
g_sig_state[sig].old_handler != (hawk_uintptr_t)SIG_DFL)
{
((hawk_main_sig_handler_t)g_sig_state[sig].old_handler) (sig);
}
}
int hawk_main_set_signal_handler (int sig, hawk_main_sig_handler_t handler, int extra_flags)
{
if (sig < 0 || sig >= HAWK_COUNTOF(g_sig_state)) return -1; /* invalid signal */
if (g_sig_state[sig].handler)
{
/* already set - allow handler change. ignore extra_flags. */
if (g_sig_state[sig].handler == (hawk_uintptr_t)handler) return -1;
g_sig_state[sig].handler = (hawk_uintptr_t)handler;
}
else
{
#if defined(HAVE_SIGACTION)
struct sigaction sa, oldsa;
if (sigaction(sig, HAWK_NULL, &oldsa) == -1) return -1;
memset(&sa, 0, HAWK_SIZEOF(sa));
if (oldsa.sa_flags & SA_SIGINFO)
{
sa.sa_sigaction = dispatch_siginfo;
sa.sa_flags = SA_SIGINFO;
}
else
{
sa.sa_handler = dispatch_signal;
sa.sa_flags = 0;
}
sa.sa_flags |= extra_flags;
/*sa.sa_flags |= SA_INTERUPT;
sa.sa_flags |= SA_RESTART;*/
sigfillset (&sa.sa_mask); /* block all signals while the handler is being executed */
if (sigaction(sig, &sa, HAWK_NULL) == -1) return -1;
g_sig_state[sig].handler = (hawk_uintptr_t)handler;
if (oldsa.sa_flags & SA_SIGINFO)
g_sig_state[sig].old_handler = (hawk_uintptr_t)oldsa.sa_sigaction;
else
g_sig_state[sig].old_handler = (hawk_uintptr_t)oldsa.sa_handler;
g_sig_state[sig].old_sa_mask = oldsa.sa_mask;
g_sig_state[sig].old_sa_flags = oldsa.sa_flags;
#else
hawk_main_sig_handler_t oh;
oh = signal(sig, dispatch_signal);
if (oh == SIG_ERR) return -1;
g_sig_state[sig].old_handler = (hawk_uintptr_t)oh;
g_sig_state[sig].handler = (hawk_uintptr_t)handler;
#endif
}
return 0;
}
int hawk_main_unset_signal_handler (int sig)
{
#if defined(HAVE_SIGACTION)
struct sigaction sa;
#endif
if (sig < 0 || sig >= HAWK_COUNTOF(g_sig_state)) return -1; /* invalid signal */
if (!g_sig_state[sig].handler) return -1; /* not set */
#if defined(HAVE_SIGACTION)
memset(&sa, 0, HAWK_SIZEOF(sa));
sa.sa_mask = g_sig_state[sig].old_sa_mask;
sa.sa_flags = g_sig_state[sig].old_sa_flags;
if (sa.sa_flags & SA_SIGINFO)
{
sa.sa_sigaction = (void(*)(int,siginfo_t*,void*))g_sig_state[sig].old_handler;
}
else
{
sa.sa_handler = (hawk_main_sig_handler_t)g_sig_state[sig].old_handler;
}
if (sigaction(sig, &sa, HAWK_NULL) == -1) return -1;
#else
if (signal(sig, (hawk_main_sig_handler_t)g_sig_state[sig].old_handler) == SIG_ERR) return -1;
#endif
g_sig_state[sig].handler = 0;
/* keep other fields untouched */
return 0;
}
/* -------------------------------------------------------- */
void hawk_main_do_nothing_on_signal (int unused)
{
/* do nothing */
}
/* -------------------------------------------------------- */
int hawk_main_collect_into_xarg (const hawk_bcs_t* path, hawk_main_xarg_t* xarg)
{
if (xarg->size <= xarg->capa)
{
hawk_bch_t** tmp;
tmp = (hawk_bch_t**)realloc(xarg->ptr, HAWK_SIZEOF(*tmp) * (xarg->capa + 128 + 1));
if (tmp == HAWK_NULL) return -1;
xarg->ptr = tmp;
xarg->capa += 128;
}
xarg->ptr[xarg->size] = strdup(path->ptr);
if (xarg->ptr[xarg->size] == HAWK_NULL) return -1;
xarg->size++;
return 0;
}
void hawk_main_purge_xarg (hawk_main_xarg_t* xarg)
{
if (xarg->ptr)
{
hawk_oow_t i;
for (i = 0; i < xarg->size; i++) free(xarg->ptr[i]);
free(xarg->ptr);
xarg->size = 0;
xarg->capa = 0;
xarg->ptr = HAWK_NULL;
}
}
int hawk_main_expand_wildcard (int argc, hawk_bch_t* argv[], int do_glob, hawk_main_xarg_t* xarg)
{
int i;
hawk_bcs_t tmp;
for (i = 0; i < argc; i++)
{
int x;
if (do_glob)
{
int glob_flags;
hawk_gem_t fake_gem; /* guly to use this fake gem here */
glob_flags = HAWK_GLOB_TOLERANT | HAWK_GLOB_PERIOD;
#if defined(_WIN32) || defined(__OS2__) || defined(__DOS__)
glob_flags |= HAWK_GLOB_NOESCAPE | HAWK_GLOB_IGNORECASE;
#endif
fake_gem.mmgr = hawk_get_sys_mmgr();
fake_gem.cmgr = hawk_get_cmgr_by_id(HAWK_CMGR_UTF8); /* TODO: system default? */
x = hawk_gem_bglob(&fake_gem, argv[i], (hawk_gem_bglob_cb_t)hawk_main_collect_into_xarg, xarg, glob_flags);
if (x <= -1) return -1;
}
else x = 0;
if (x == 0)
{
/* not expanded. just use it as is */
tmp.ptr = argv[i];
tmp.len = hawk_count_bcstr(argv[i]);
if (hawk_main_collect_into_xarg(&tmp, xarg) <= -1) return -1;
}
}
xarg->ptr[xarg->size] = HAWK_NULL;
return 0;
}
/* -------------------------------------------------------- */
#if !defined(HAWK_PATH_MAX)
#define HAWK_PATH_MAX (4096)
#endif
int hawk_main_load_lang (hawk_pocat_t* pc, const char* basedir, const char* subbasedir, const char* prefix, const char* suffix, const char* locale)
{
char path[HAWK_PATH_MAX];
const char* marker;
const char markers[] = { '@', '_' };
hawk_oow_t len, xlen, zlen, i;
len = 0;
if (basedir) len += hawk_copy_bcstr(&path[len], HAWK_COUNTOF(path) - len, basedir);
if (subbasedir) len += hawk_copy_bcstr(&path[len], HAWK_COUNTOF(path) - len, subbasedir);
if (prefix) len += hawk_copy_bcstr(&path[len], HAWK_COUNTOF(path) - len, prefix);
xlen = len;
marker = hawk_rfind_bchar_in_bcstr(locale, '.');
zlen = marker? (marker - locale): hawk_count_bcstr(locale);
for (i = 0; i < HAWK_COUNTOF(markers); i++)
{
marker = hawk_rfind_bchar_in_bchars(locale, zlen, markers[i]);
if (marker)
{
len = xlen;
len += hawk_copy_bchars_to_bcstr(&path[len], HAWK_COUNTOF(path) - len, locale, zlen);
if (suffix) len += hawk_copy_bcstr(&path[len], HAWK_COUNTOF(path) - len, suffix);
if (hawk_pocat_load_file(pc, path, HAWK_NULL, 0) >= 0) return 0;
zlen = marker - locale;
}
}
len = xlen;
len += hawk_copy_bchars_to_bcstr(&path[len], HAWK_COUNTOF(path) - len, locale, zlen);
len += hawk_copy_bcstr(&path[len], HAWK_COUNTOF(path) - len, suffix);
if (hawk_pocat_load_file(pc, path, HAWK_NULL, 0) >= 0) return 0;
return -1;
}
static void load_lang (void)
{
memset(&main_pocat_gem, 0, sizeof(main_pocat_gem));
main_pocat_gem.mmgr = hawk_get_sys_mmgr();
main_pocat_gem.cmgr = hawk_get_cmgr_by_id(HAWK_CMGR_UTF8);
main_pocat = hawk_pocat_open(&main_pocat_gem, 0);
if (main_pocat)
{
const char* homedir;
const char* xdgdatahome;
const char* lang;
homedir = getenv("HOME"); /* TODO: get it from user entry? */
xdgdatahome = getenv("XDG_DATA_HOME");
lang = getenv("LANG");
if (!lang) goto lang_load_exit;
if (xdgdatahome && hawk_main_load_lang(main_pocat, xdgdatahome, "/hawk/lang", "/hawk-", ".po", lang) >= 0) goto lang_load_exit;
if (!xdgdatahome && homedir && hawk_main_load_lang(main_pocat, homedir, HOMELANGDIR, "/hawk-", ".po", lang) >= 0) goto lang_load_exit;
if (hawk_main_load_lang(main_pocat, LANGDIR, HAWK_NULL, "/hawk-", ".po", lang) >= 0) goto lang_load_exit;
lang_load_exit:
/* nothing */ ;
}
}
static void unload_lang (void)
{
if (main_pocat)
{
hawk_pocat_close(main_pocat);
main_pocat = HAWK_NULL;
}
memset(&main_pocat_gem, 0, sizeof(main_pocat_gem));
}
/* -------------------------------------------------------- */
void hawk_main_print_xma (void* ctx, const hawk_bch_t* fmt, ...)
{
va_list ap;
va_start (ap, fmt);
vfprintf (stderr, fmt, ap);
va_end (ap);
}
/* -------------------------------------------------------- */
void hawk_main_print_error (const hawk_bch_t* fmt, ...)
{
va_list va;
fprintf (stderr, "ERROR: ");
va_start (va, fmt);
vfprintf (stderr, fmt, va);
va_end (va);
}
void hawk_main_print_warning (const hawk_bch_t* fmt, ...)
{
va_list va;
fprintf (stderr, "WARNING: ");
va_start (va, fmt);
vfprintf (stderr, fmt, va);
va_end (va);
}
/* -------------------------------------------------------- */
static int main_version(int argc, hawk_bch_t* argv[], const hawk_bch_t* real_argv0)
{
printf("%s %s\n", hawk_get_base_name_bcstr(real_argv0), HAWK_PACKAGE_VERSION);
printf("Copyright 2006-2022 Chung, Hyung-Hwan\n");
return 0;
}
static void print_usage(FILE* out, const hawk_bch_t* real_argv0)
{
const hawk_bch_t* b1 = hawk_get_base_name_bcstr(real_argv0);
fprintf(out, "%s: %s %s\n", _("USAGE"), b1, _("[options] [mode specific options and parameters]"));
fprintf(out, "%s\n", _("Options as follows:"));
fprintf(out, "%s\n", _(" --usage print this message"));
fprintf(out, "%s\n", _(" --version print version"));
fprintf(out, "%s\n", _(" --awk/--hawk switch to the awk mode(default)"));
fprintf(out, "%s\n", _(" --cut switch to the cut mode"));
fprintf(out, "%s\n", _(" --sed switch to the sed mode"));
}
static int main_usage(int argc, hawk_bch_t* argv[], const hawk_bch_t* real_argv0)
{
print_usage(stdout, real_argv0);
return 0;
}
static struct {
const hawk_bch_t* name;
int (*main) (int argc, hawk_bch_t* argv[], const hawk_bch_t* real_argv0);
} entry_funcs[] = {
{ "awk", main_hawk },
{ "cut", main_cut },
{ "hawk", main_hawk },
{ "sed", main_sed },
{ "usage", main_usage },
{ "version", main_version }
};
int main(int argc, hawk_bch_t* argv[])
{
int ret = -1;
#if defined(_WIN32)
char locale[100];
UINT codepage;
WSADATA wsadata;
int sock_inited = 0;
#elif defined(__DOS__)
extern BOOL _watt_do_exit;
int sock_inited = 0;
#else
/* nothing special */
#endif
#if defined(_WIN32)
codepage = GetConsoleOutputCP();
if (codepage == CP_UTF8)
{
/*SetConsoleOUtputCP(CP_UTF8);*/
/*hawk_setdflcmgrbyid(HAWK_CMGR_UTF8);*/
}
else
{
/* .codepage */
hawk_fmt_uintmax_to_bcstr(locale, HAWK_COUNTOF(locale), codepage, 10, -1, '\0', ".");
setlocale(LC_ALL, locale);
/* hawk_setdflcmgrbyid(HAWK_CMGR_SLMB); */
}
#else
setlocale(LC_ALL, "");
/* hawk_setdflcmgrbyid(HAWK_CMGR_SLMB); */
#endif
load_lang();
#if defined(_WIN32)
if (WSAStartup(MAKEWORD(2,0), &wsadata) != 0)
hawk_main_print_warning("Failed to start up winsock\n");
else sock_inited = 1;
#elif defined(__DOS__)
/* TODO: add an option to skip watt-32 */
_watt_do_exit = 0; /* prevent sock_init from exiting upon failure */
if (sock_init() != 0) hawk_main_print_warning("Failed to initialize watt-32\n");
else sock_inited = 1;
#endif
if (argc >= 2)
{
hawk_oow_t i;
const hawk_bch_t* first_opt = argv[1];
for (i = 0; i < HAWK_COUNTOF(entry_funcs); i++) {
if (first_opt[0] == '-' && first_opt[1] == '-' && hawk_comp_bcstr(&first_opt[2], entry_funcs[i].name, 0) == 0) {
/* [NOTE]
* if hawk is invoked via 'hawk --awk' or 'hawk --hawk',
* the value ARGV[0] inside a hawk script is "--awk" or "--hawk" */
ret = entry_funcs[i].main(argc -1, &argv[1], argv[0]);
goto done;
}
}
}
ret = main_hawk(argc, argv, HAWK_NULL);
done:
#if defined(_WIN32)
if (sock_inited) WSACleanup();
#elif defined(__DOS__)
if (sock_inited) sock_exit();
#endif
unload_lang();
return ret;
}
/* ---------------------------------------------------------------------- */
#if defined(FAKE_SOCKET)
socket () {}
listen () {}
accept () {}
recvfrom () {}
connect () {}
getsockopt () {}
recv () {}
setsockopt () {}
send () {}
bind () {}
shutdown () {}
void* memmove (void* x, void* y, size_t z) {}
#endif