#include <bsd/bsd.h>
#include <mksh/i18n.h>
#include <mksh/misc.h>
#include <stdarg.h>
#include <stdlib.h>
#include <sys/signal.h>
#include <sys/wait.h>
#include <string.h>
#include <libintl.h>
extern "C" {
void (*sigivalue)(int) = SIG_DFL;
void (*sigqvalue)(int) = SIG_DFL;
void (*sigtvalue)(int) = SIG_DFL;
void (*sighvalue)(int) = SIG_DFL;
}
long getname_bytes_count = 0;
long getname_names_count = 0;
long getname_struct_count = 0;
long freename_bytes_count = 0;
long freename_names_count = 0;
long freename_struct_count = 0;
long expandstring_count = 0;
long getwstring_count = 0;
static void expand_string(String string, int length);
#define FATAL_ERROR_MSG_SIZE 200
char *
getmem(size_t size)
{
char *result = (char *)malloc(size);
if (result == NULL) {
(void) fprintf(stderr, "*** Error: malloc(%d) failed: %s\n%s",
size, strerror(errno),
gettext("mksh: Fatal error: Out of memory\n"));
exit(1);
}
return (result);
}
void
retmem(wchar_t *p)
{
(void) free((char *) p);
}
void
retmem_mb(caddr_t p)
{
(void) free(p);
}
Name
getname_fn(wchar_t *name, int len, Boolean dont_enter, Boolean * foundp)
{
int length;
wchar_t *cap = name;
Name np;
static Name_rec empty_Name;
char *tmp_mbs_buffer = NULL;
char *mbs_name = mbs_buffer;
if (len == FIND_LENGTH) {
length = wcslen(name);
} else {
length = len;
}
Wstring ws;
ws.init(name, length);
if (length >= MAXPATHLEN) {
mbs_name = tmp_mbs_buffer = getmem((length * MB_LEN_MAX) + 1);
}
(void) wcstombs(mbs_name, ws.get_string(), (length * MB_LEN_MAX) + 1);
if (dont_enter || (foundp != 0)) {
np = hashtab.lookup(mbs_name);
if (foundp != 0) {
*foundp = (np != 0) ? true : false;
}
if ((np != 0) || dont_enter) {
if(tmp_mbs_buffer != NULL) {
retmem_mb(tmp_mbs_buffer);
}
return np;
} else {
np = ALLOC(Name);
}
} else {
Boolean found;
np = hashtab.insert(mbs_name, found);
if (found) {
if(tmp_mbs_buffer != NULL) {
retmem_mb(tmp_mbs_buffer);
}
return np;
}
}
getname_struct_count += sizeof(struct _Name);
*np = empty_Name;
np->string_mb = strdup(mbs_name);
if(tmp_mbs_buffer != NULL) {
retmem_mb(tmp_mbs_buffer);
mbs_name = tmp_mbs_buffer = NULL;
}
getname_bytes_count += strlen(np->string_mb) + 1;
np->stat.time = file_no_time;
np->hash.length = length;
for (cap = name, len = 0; --length >= 0;) {
len |= get_char_semantics_value(*cap++);
}
np->dollar = BOOLEAN((len & (int) dollar_sem) != 0);
np->meta = BOOLEAN((len & (int) meta_sem) != 0);
np->percent = BOOLEAN((len & (int) percent_sem) != 0);
np->wildcard = BOOLEAN((len & (int) wildcard_sem) != 0);
np->colon = BOOLEAN((len & (int) colon_sem) != 0);
np->parenleft = BOOLEAN((len & (int) parenleft_sem) != 0);
getname_names_count++;
return np;
}
void
store_name(Name name)
{
hashtab.insert(name);
}
void
free_name(Name name)
{
freename_names_count++;
freename_struct_count += sizeof(struct _Name);
freename_bytes_count += strlen(name->string_mb) + 1;
retmem_mb(name->string_mb);
for (Property next, p = name->prop; p != NULL; p = next) {
next = p->next;
free(p);
}
free(name);
}
void
enable_interrupt(void (*handler) (int))
{
if (sigivalue != SIG_IGN) {
(void) bsd_signal(SIGINT, (SIG_PF) handler);
}
if (sigqvalue != SIG_IGN) {
(void) bsd_signal(SIGQUIT, (SIG_PF) handler);
}
if (sigtvalue != SIG_IGN) {
(void) bsd_signal(SIGTERM, (SIG_PF) handler);
}
if (sighvalue != SIG_IGN) {
(void) bsd_signal(SIGHUP, (SIG_PF) handler);
}
}
void
setup_char_semantics(void)
{
const char *s;
wchar_t wc_buffer[1];
int entry;
if (svr4) {
s = "@-";
} else {
s = "=@-?!+";
}
for (s; MBTOWC(wc_buffer, s); s++) {
entry = get_char_semantics_entry(*wc_buffer);
char_semantics[entry] |= (int) command_prefix_sem;
}
char_semantics[dollar_char_entry] |= (int) dollar_sem;
for (s = "#|=^();&<>*?[]:$`'\"\\\n"; MBTOWC(wc_buffer, s); s++) {
entry = get_char_semantics_entry(*wc_buffer);
char_semantics[entry] |= (int) meta_sem;
}
char_semantics[percent_char_entry] |= (int) percent_sem;
for (s = "@*<%?^"; MBTOWC(wc_buffer, s); s++) {
entry = get_char_semantics_entry(*wc_buffer);
char_semantics[entry] |= (int) special_macro_sem;
}
for (s = "?[*"; MBTOWC(wc_buffer, s); s++) {
entry = get_char_semantics_entry(*wc_buffer);
char_semantics[entry] |= (int) wildcard_sem;
}
char_semantics[colon_char_entry] |= (int) colon_sem;
char_semantics[parenleft_char_entry] |= (int) parenleft_sem;
}
char *
errmsg(int errnum)
{
char *msg;
char *errbuf;
errno = 0;
msg = strerror(errnum);
if (errno == EINVAL) {
size_t size = 6 + 1 + 11 + 1;
errbuf = getmem(size);
(void) snprintf(errbuf, size, gettext("Error %d"), errnum);
return (errbuf);
}
return (msg);
}
static char static_buf[MAXPATHLEN*3];
void
fatal_mksh(const char *message, ...)
{
va_list args;
char *buf = static_buf;
char *mksh_fat_err = gettext("mksh: Fatal error: ");
char *cur_wrk_dir = gettext("Current working directory: ");
int mksh_fat_err_len = strlen(mksh_fat_err);
va_start(args, message);
(void) fflush(stdout);
(void) strcpy(buf, mksh_fat_err);
size_t buf_len = vsnprintf(static_buf + mksh_fat_err_len,
sizeof(static_buf) - mksh_fat_err_len,
message, args)
+ mksh_fat_err_len
+ strlen(cur_wrk_dir)
+ strlen(get_current_path_mksh())
+ 3;
va_end(args);
if (buf_len >= sizeof(static_buf)) {
buf = getmem(buf_len);
(void) strcpy(buf, mksh_fat_err);
va_start(args, message);
(void) vsprintf(buf + mksh_fat_err_len, message, args);
va_end(args);
}
(void) strcat(buf, "\n");
if (1) {
(void) strcat(buf, cur_wrk_dir);
(void) strcat(buf, get_current_path_mksh());
(void) strcat(buf, "\n");
}
(void) fputs(buf, stderr);
(void) fflush(stderr);
if (buf != static_buf) {
retmem_mb(buf);
}
exit_status = 1;
exit(1);
}
void
fatal_reader_mksh(const char * pattern, ...)
{
va_list args;
char message[1000];
va_start(args, pattern);
(void) fflush(stdout);
(void) fprintf(stderr, gettext("mksh: Fatal error in reader: "));
(void) vfprintf(stderr, pattern, args);
(void) fprintf(stderr, "\n");
va_end(args);
if (1) {
(void) fprintf(stderr,
gettext("Current working directory %s\n"),
get_current_path_mksh());
}
(void) fflush(stderr);
exit_status = 1;
exit(1);
}
void
warning_mksh(char * message, ...)
{
va_list args;
va_start(args, message);
(void) fflush(stdout);
(void) fprintf(stderr, gettext("mksh: Warning: "));
(void) vfprintf(stderr, message, args);
(void) fprintf(stderr, "\n");
va_end(args);
if (1) {
(void) fprintf(stderr,
gettext("Current working directory %s\n"),
get_current_path_mksh());
}
(void) fflush(stderr);
}
char *
get_current_path_mksh(void)
{
char pwd[(MAXPATHLEN * MB_LEN_MAX)];
static char *current_path;
if (current_path == NULL) {
getcwd(pwd, sizeof(pwd));
if (pwd[0] == (int) nul_char) {
pwd[0] = (int) slash_char;
pwd[1] = (int) nul_char;
}
current_path = strdup(pwd);
}
return current_path;
}
Property
append_prop(Name target, Property_id type)
{
Property *insert = &target->prop;
Property prop = *insert;
int size;
switch (type) {
case conditional_prop:
size = sizeof (struct Conditional);
break;
case line_prop:
size = sizeof (struct Line);
break;
case macro_prop:
size = sizeof (struct _Macro);
break;
case makefile_prop:
size = sizeof (struct Makefile);
break;
case member_prop:
size = sizeof (struct Member);
break;
case recursive_prop:
size = sizeof (struct Recursive);
break;
case sccs_prop:
size = sizeof (struct Sccs);
break;
case suffix_prop:
size = sizeof (struct Suffix);
break;
case target_prop:
size = sizeof (struct Target);
break;
case time_prop:
size = sizeof (struct STime);
break;
case vpath_alias_prop:
size = sizeof (struct Vpath_alias);
break;
case long_member_name_prop:
size = sizeof (struct Long_member_name);
break;
case macro_append_prop:
size = sizeof (struct _Macro_appendix);
break;
case env_mem_prop:
size = sizeof (struct _Env_mem);
break;
default:
fatal_mksh(gettext("Internal error. Unknown prop type %d"), type);
}
for (; prop != NULL; insert = &prop->next, prop = *insert);
size += PROPERTY_HEAD_SIZE;
*insert = prop = (Property) getmem(size);
memset((char *) prop, 0, size);
prop->type = type;
prop->next = NULL;
return prop;
}
Property
maybe_append_prop(Name target, Property_id type)
{
Property prop;
if ((prop = get_prop(target->prop, type)) != NULL) {
return prop;
}
return append_prop(target, type);
}
Property
get_prop(Property start, Property_id type)
{
for (; start != NULL; start = start->next) {
if (start->type == type) {
return start;
}
}
return NULL;
}
void
append_string(wchar_t *from, String to, int length)
{
if (length == FIND_LENGTH) {
length = wcslen(from);
}
if (to->buffer.start == NULL) {
expand_string(to, 32 + length);
}
if (to->buffer.end - to->text.p <= length) {
expand_string(to,
(to->buffer.end - to->buffer.start) * 2 +
length);
}
if (length > 0) {
(void) wcsncpy(to->text.p, from, length);
to->text.p += length;
}
*(to->text.p) = (int) nul_char;
}
wchar_t * get_wstring(char *from) {
if(from == NULL) {
return NULL;
}
getwstring_count++;
wchar_t * wcbuf = ALLOC_WC(strlen(from) + 1);
mbstowcs(wcbuf, from, strlen(from)+1);
return wcbuf;
}
void
append_string(char *from, String to, int length)
{
if (length == FIND_LENGTH) {
length = strlen(from);
}
if (to->buffer.start == NULL) {
expand_string(to, 32 + length);
}
if (to->buffer.end - to->text.p <= length) {
expand_string(to,
(to->buffer.end - to->buffer.start) * 2 +
length);
}
if (length > 0) {
(void) mbstowcs(to->text.p, from, length);
to->text.p += length;
}
*(to->text.p) = (int) nul_char;
}
static void
expand_string(String string, int length)
{
wchar_t *p;
if (string->buffer.start == NULL) {
string->buffer.start =
string->text.p =
string->text.end =
ALLOC_WC(length);
string->buffer.end = string->buffer.start + length;
string->text.p[0] = (int) nul_char;
string->free_after_use = true;
expandstring_count++;
return;
}
if (string->buffer.end - string->buffer.start >= length) {
return;
}
expandstring_count++;
p = ALLOC_WC(length);
(void) wcscpy(p, string->buffer.start);
string->text.p = p + (string->text.p - string->buffer.start);
string->text.end = p + (string->text.end - string->buffer.start);
string->buffer.end = p + length;
if (string->free_after_use) {
retmem(string->buffer.start);
}
string->buffer.start = p;
string->free_after_use = true;
}
void
append_char(wchar_t from, String to)
{
if (to->buffer.start == NULL) {
expand_string(to, 32);
}
if (to->buffer.end - to->text.p <= 2) {
expand_string(to, to->buffer.end - to->buffer.start + 32);
}
*(to->text.p)++ = from;
*(to->text.p) = (int) nul_char;
}
void
handle_interrupt_mksh(int)
{
(void) fflush(stdout);
if (childPid > 0) {
kill(childPid, SIGTERM);
childPid = -1;
}
while (wait((int *) NULL) != -1);
exit_status = 2;
exit(2);
}
void
setup_interrupt(void (*handler) (int))
{
sigivalue = bsd_signal(SIGINT, SIG_IGN);
sigqvalue = bsd_signal(SIGQUIT, SIG_IGN);
sigtvalue = bsd_signal(SIGTERM, SIG_IGN);
sighvalue = bsd_signal(SIGHUP, SIG_IGN);
enable_interrupt(handler);
}
void
mbstowcs_with_check(wchar_t *pwcs, const char *s, size_t n)
{
if(mbstowcs(pwcs, s, n) == -1) {
fatal_mksh(gettext("The string `%s' is not valid in current locale"), s);
}
}
Wstring::Wstring()
{
INIT_STRING_FROM_STACK(string, string_buf);
}
Wstring::Wstring(struct _Name * name)
{
INIT_STRING_FROM_STACK(string, string_buf);
append_string(name->string_mb, &string, name->hash.length);
}
Wstring::~Wstring()
{
if(string.free_after_use) {
retmem(string.buffer.start);
}
}
void
Wstring::init(struct _Name * name)
{
if(string.free_after_use) {
retmem(string.buffer.start);
}
INIT_STRING_FROM_STACK(string, string_buf);
append_string(name->string_mb, &string, name->hash.length);
}
void
Wstring::init(wchar_t * name, unsigned length)
{
INIT_STRING_FROM_STACK(string, string_buf);
append_string(name, &string, length);
string.buffer.start[length] = 0;
}
Boolean
Wstring::equaln(wchar_t * str, unsigned length)
{
return (Boolean)IS_WEQUALN(string.buffer.start, str, length);
}
Boolean
Wstring::equaln(Wstring * str, unsigned length)
{
return (Boolean)IS_WEQUALN(string.buffer.start, str->string.buffer.start, length);
}
Boolean
Wstring::equal(wchar_t * str, unsigned off, unsigned length)
{
return (Boolean)IS_WEQUALN(string.buffer.start + off, str, length);
}
Boolean
Wstring::equal(wchar_t * str, unsigned off)
{
return (Boolean)IS_WEQUAL(string.buffer.start + off, str);
}
Boolean
Wstring::equal(wchar_t * str)
{
return equal(str, 0);
}
Boolean
Wstring::equal(Wstring * str, unsigned off, unsigned length)
{
return (Boolean)IS_WEQUALN(string.buffer.start + off, str->string.buffer.start, length);
}
Boolean
Wstring::equal(Wstring * str)
{
return equal(str, 0);
}
Boolean
Wstring::equal(Wstring * str, unsigned off)
{
return (Boolean)IS_WEQUAL(string.buffer.start + off, str->string.buffer.start);
}
void
Wstring::append_to_str(struct _String * str, unsigned off, unsigned length)
{
append_string(string.buffer.start + off, str, length);
}
Name
Name_set::lookup(const char *key)
{
for (entry *node = root; node != 0;) {
int res = strcmp(key, node->name->string_mb);
if (res < 0) {
node = node->left;
} else if (res > 0) {
node = node->right;
} else {
return node->name;
}
}
return 0;
}
Name
Name_set::insert(const char *key, Boolean &found)
{
Name name = 0;
if (root != 0) {
for (entry *node = root; name == 0;) {
int res = strcmp(key, node->name->string_mb);
if (res < 0) {
if (node->left != 0) {
node = node->left;
} else {
found = false;
name = ALLOC(Name);
node->left = new entry(name, node);
rebalance(node);
}
} else if (res > 0) {
if (node->right != 0) {
node = node->right;
} else {
found = false;
name = ALLOC(Name);
node->right = new entry(name, node);
rebalance(node);
}
} else {
found = true;
name = node->name;
}
}
} else {
found = false;
name = ALLOC(Name);
root = new entry(name, 0);
}
return name;
}
void
Name_set::insert(Name name) {
if (root != 0) {
for (entry *node = root;;) {
int res = strcmp(name->string_mb, node->name->string_mb);
if (res < 0) {
if (node->left != 0) {
node = node->left;
} else {
node->left = new entry(name, node);
rebalance(node);
break;
}
} else if (res > 0) {
if (node->right != 0) {
node = node->right;
} else {
node->right = new entry(name, node);
rebalance(node);
break;
}
} else {
break;
}
}
} else {
root = new entry(name, 0);
}
}
void
Name_set::rebalance(Name_set::entry *node) {
for (; node != 0; node = node->parent) {
entry *right = node->right;
entry *left = node->left;
unsigned rdepth = (right != 0) ? right->depth : 0;
unsigned ldepth = (left != 0) ? left->depth : 0;
if (ldepth > rdepth + 1) {
if ((node->left = left->right) != 0) {
left->right->parent = node;
}
if ((left->parent = node->parent) != 0) {
if (node == node->parent->right) {
node->parent->right = left;
} else {
node->parent->left = left;
}
} else {
root = left;
}
left->right = node;
node->parent = left;
node->setup_depth();
node = left;
} else if (rdepth > ldepth + 1) {
if ((node->right = right->left) != 0) {
right->left->parent = node;
}
if ((right->parent = node->parent) != 0) {
if (node == node->parent->right) {
node->parent->right = right;
} else {
node->parent->left = right;
}
} else {
root = right;
}
right->left = node;
node->parent = right;
node->setup_depth();
node = right;
}
node->setup_depth();
}
}
Name_set::iterator
Name_set::begin() const {
for (entry *node = root; node != 0; node = node->left) {
if (node->left == 0) {
return iterator(node);
}
}
return iterator();
}
Name_set::iterator&
Name_set::iterator::operator++() {
if (node != 0) {
if (node->right != 0) {
node = node->right;
while (node->left != 0) {
node = node->left;
}
} else {
while ((node->parent != 0) && (node->parent->right == node)) {
node = node->parent;
}
node = node->parent;
}
}
return *this;
}