429 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			429 lines
		
	
	
		
			11 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-glob.h>
 | 
						|
#include <hawk-xma.h>
 | 
						|
#include <stdio.h>
 | 
						|
#include <locale.h>
 | 
						|
#include <string.h>
 | 
						|
#include <stdlib.h>
 | 
						|
 | 
						|
#if defined(_WIN32)
 | 
						|
#	include <windows.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
 | 
						|
/* ---------------------------------------------------------------------- */
 | 
						|
 | 
						|
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)
 | 
						|
{
 | 
						|
	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 (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
 | 
						|
		g_sig_state[sig].old_handler = (hawk_uintptr_t)signal(sig, handler);
 | 
						|
		g_sig_state[sig].handler = (hawk_uintptr_t)dispatch_signal;
 | 
						|
	#endif
 | 
						|
	}
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
int hawk_main_unset_signal_handler (int sig)
 | 
						|
{
 | 
						|
#if defined(HAVE_SIGACTION)
 | 
						|
	struct sigaction sa;
 | 
						|
#endif
 | 
						|
 | 
						|
	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
 | 
						|
	signal (sig, (hawk_main_sig_handler_t)g_sig_state[sig].old_handler);
 | 
						|
#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;
 | 
						|
}
 | 
						|
 | 
						|
/* -------------------------------------------------------- */
 | 
						|
 | 
						|
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, "USAGE: %s [options] [mode specific options and parameters]\n", b1);
 | 
						|
	fprintf (out, "Options as follows:\n");
 | 
						|
	fprintf (out, " --usage                          print this message\n");
 | 
						|
	fprintf (out, " --version                        print version\n");
 | 
						|
	fprintf (out, " --awk/--hawk                     switch to the awk mode(default)\n");
 | 
						|
	fprintf (out, " --sed                            switch to the sed mode\n");
 | 
						|
}
 | 
						|
 | 
						|
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;
 | 
						|
 | 
						|
#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
 | 
						|
 | 
						|
#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
 | 
						|
 | 
						|
	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
 |