#include <dirent.h>
#include <errno.h>
#include <mk/defs.h>
#include <mksh/macro.h>
#include <mksh/misc.h>
#include <sys/stat.h>
#include <libintl.h>
extern timestruc_t& exists(Name target);
extern void set_target_stat(Name target, struct stat buf);
static timestruc_t& vpath_exists(Name target);
static Name enter_file_name(wchar_t *name_string, wchar_t *library);
static Boolean star_match(char *string, char *pattern);
static Boolean amatch(wchar_t *string, wchar_t *pattern);
timestruc_t&
exists(Name target)
{
struct stat buf;
int result;
if (target->stat.time != file_no_time) {
return target->stat.time;
}
if (target->is_member &&
(get_prop(target->prop, member_prop) != NULL)) {
return read_archive(target);
}
if (debug_level > 1) {
(void) printf("%*sstat(%s)\n",
recursion_level,
"",
target->string_mb);
}
result = lstat_vroot(target->string_mb, &buf, NULL, VROOT_DEFAULT);
if ((result != -1) && ((buf.st_mode & S_IFMT) == S_IFLNK)) {
target->stat.is_sym_link = true;
result = stat_vroot(target->string_mb, &buf, NULL, VROOT_DEFAULT);
} else {
target->stat.is_sym_link = false;
}
if (result < 0) {
target->stat.time = file_doesnt_exist;
target->stat.stat_errno = errno;
if ((errno == ENOENT) &&
vpath_defined &&
(target->string_mb[0] != (int) slash_char) ) {
vpath_exists(target);
}
} else {
target->stat.stat_errno = 0;
target->stat.is_file = true;
target->stat.mode = buf.st_mode & 0777;
target->stat.size = buf.st_size;
target->stat.is_dir =
BOOLEAN((buf.st_mode & S_IFMT) == S_IFDIR);
if (target->stat.is_dir) {
target->stat.time = file_is_dir;
} else {
target->stat.time = MAX(buf.st_mtim, file_min_time);
}
}
if ((target->colon_splits > 0) &&
(get_prop(target->prop, time_prop) == NULL)) {
append_prop(target, time_prop)->body.time.time =
target->stat.time;
}
return target->stat.time;
}
void
set_target_stat(Name target, struct stat buf)
{
target->stat.stat_errno = 0;
target->stat.is_file = true;
target->stat.mode = buf.st_mode & 0777;
target->stat.size = buf.st_size;
target->stat.is_dir =
BOOLEAN((buf.st_mode & S_IFMT) == S_IFDIR);
if (target->stat.is_dir) {
target->stat.time = file_is_dir;
} else {
target->stat.time = MAX(buf.st_mtim, file_min_time);
}
}
static timestruc_t&
vpath_exists(Name target)
{
wchar_t *vpath;
wchar_t file_name[MAXPATHLEN];
wchar_t *name_p;
Name alias;
vpath_defined = false;
Wstring wcb(getvar(vpath_name));
Wstring wcb1(target);
vpath = wcb.get_string();
while (*vpath != (int) nul_char) {
name_p = file_name;
while ((*vpath != (int) colon_char) &&
(*vpath != (int) nul_char)) {
*name_p++ = *vpath++;
}
*name_p++ = (int) slash_char;
(void) wcscpy(name_p, wcb1.get_string());
alias = GETNAME(file_name, FIND_LENGTH);
if (exists(alias) != file_doesnt_exist) {
target->stat.is_file = true;
target->stat.mode = alias->stat.mode;
target->stat.size = alias->stat.size;
target->stat.is_dir = alias->stat.is_dir;
target->stat.time = alias->stat.time;
maybe_append_prop(target, vpath_alias_prop)->
body.vpath_alias.alias = alias;
target->has_vpath_alias_prop = true;
vpath_defined = true;
return alias->stat.time;
}
while ((*vpath != (int) nul_char) &&
((*vpath == (int) colon_char) || iswspace(*vpath))) {
vpath++;
}
}
vpath_defined = true;
return target->stat.time;
}
int
read_dir(Name dir, wchar_t *pattern, Property line, wchar_t *library)
{
wchar_t file_name[MAXPATHLEN];
wchar_t *file_name_p = file_name;
Name file;
wchar_t plain_file_name[MAXPATHLEN];
wchar_t *plain_file_name_p;
Name plain_file;
wchar_t tmp_wcs_buffer[MAXPATHLEN];
DIR *dir_fd;
int m_local_dependency=0;
#define d_fileno d_ino
struct dirent *dp;
wchar_t *vpath = NULL;
wchar_t *p;
int result = 0;
if(dir->hash.length >= MAXPATHLEN) {
return 0;
}
Wstring wcb(dir);
Wstring vps;
if (pattern == NULL) {
if (dir->has_read_dir) {
return 0;
}
dir->has_read_dir = true;
}
if (vpath_defined && (dir == dot)) {
vps.init(getvar(vpath_name));
vpath = vps.get_string();
}
if ((dir->hash.length > 1) || (wcb.get_string()[0] != (int) period_char)) {
(void) wcscpy(file_name, wcb.get_string());
MBSTOWCS(wcs_buffer, "/");
(void) wcscat(file_name, wcs_buffer);
file_name_p = file_name + wcslen(file_name);
}
vpath_loop:
dir_fd = opendir(dir->string_mb);
if (dir_fd == NULL) {
return 0;
}
while ((dp = readdir(dir_fd)) != NULL) {
if ((dp->d_fileno == 0) ||
((dp->d_name[0] == (int) period_char) &&
((dp->d_name[1] == 0) ||
((dp->d_name[1] == (int) period_char) &&
(dp->d_name[2] == 0))))) {
continue;
}
MBSTOWCS(tmp_wcs_buffer, dp->d_name);
(void) wcscpy(file_name_p, tmp_wcs_buffer);
file = enter_file_name(file_name, library);
if ((pattern != NULL) && amatch(tmp_wcs_buffer, pattern)) {
if (debug_level > 0){
WCSTOMBS(mbs_buffer, pattern);
(void) printf(gettext("'%s: %s' due to %s expansion\n"),
line->body.line.target->string_mb,
file->string_mb,
mbs_buffer);
}
enter_dependency(line, file, false);
result++;
} else {
file->stat.has_sccs = NO_SCCS;
if ((dp->d_name[0] == 's') &&
(dp->d_name[1] == (int) period_char)) {
MBSTOWCS(tmp_wcs_buffer, dp->d_name + 2);
plain_file_name_p = plain_file_name;
(void) wcscpy(plain_file_name_p, tmp_wcs_buffer);
plain_file = GETNAME(plain_file_name, FIND_LENGTH);
plain_file->stat.is_file = true;
plain_file->stat.has_sccs = HAS_SCCS;
maybe_append_prop(plain_file, sccs_prop)->
body.sccs.file = file;
MBSTOWCS(tmp_wcs_buffer, dp->d_name + 2);
if ((pattern != NULL) &&
amatch(tmp_wcs_buffer, pattern)) {
if (debug_level > 0) {
WCSTOMBS(mbs_buffer, pattern);
(void) printf(gettext("'%s: %s' due to %s expansion\n"),
line->body.line.target->
string_mb,
plain_file->string_mb,
mbs_buffer);
}
enter_dependency(line, plain_file, false);
result++;
}
}
}
}
(void) closedir(dir_fd);
if ((vpath != NULL) && (*vpath != (int) nul_char)) {
while ((*vpath != (int) nul_char) &&
(iswspace(*vpath) || (*vpath == (int) colon_char))) {
vpath++;
}
p = vpath;
while ((*vpath != (int) colon_char) &&
(*vpath != (int) nul_char)) {
vpath++;
}
if (vpath > p) {
dir = GETNAME(p, vpath - p);
goto vpath_loop;
}
}
(void) wcsncpy(plain_file_name,
file_name,
file_name_p - file_name);
plain_file_name[file_name_p - file_name] = 0;
plain_file_name_p = plain_file_name + wcslen(plain_file_name);
if(!svr4) {
if (sccs_dir_path != NULL) {
wchar_t tmp_wchar;
wchar_t path[MAXPATHLEN];
char mb_path[MAXPATHLEN];
if (file_name_p - file_name > 0) {
tmp_wchar = *file_name_p;
*file_name_p = 0;
WCSTOMBS(mbs_buffer, file_name);
(void) sprintf(mb_path, "%s/%s/SCCS",
sccs_dir_path,
mbs_buffer);
*file_name_p = tmp_wchar;
} else {
(void) sprintf(mb_path, "%s/SCCS", sccs_dir_path);
}
MBSTOWCS(path, mb_path);
(void) wcscpy(file_name, path);
} else {
MBSTOWCS(wcs_buffer, "SCCS");
(void) wcscpy(file_name_p, wcs_buffer);
}
} else {
MBSTOWCS(wcs_buffer, ".");
(void) wcscpy(file_name_p, wcs_buffer);
}
(void) exists(dir = GETNAME(file_name, FIND_LENGTH));
if (!dir->stat.is_file) {
return result;
}
dir_fd = opendir(dir->string_mb);
if (dir_fd == NULL) {
return result;
}
MBSTOWCS(wcs_buffer, "/");
(void) wcscat(file_name, wcs_buffer);
file_name_p = file_name + wcslen(file_name);
while ((dp = readdir(dir_fd)) != NULL) {
if ((dp->d_fileno == 0) ||
((dp->d_name[0] == (int) period_char) &&
((dp->d_name[1] == 0) ||
((dp->d_name[1] == (int) period_char) &&
(dp->d_name[2] == 0))))) {
continue;
}
MBSTOWCS(wcs_buffer, dp->d_name);
(void) wcscpy(file_name_p, wcs_buffer);
file = GETNAME(file_name, FIND_LENGTH);
file->stat.is_file = true;
file->stat.has_sccs = NO_SCCS;
if ((dp->d_name[0] == 's') &&
(dp->d_name[1] == (int) period_char)) {
MBSTOWCS(wcs_buffer, dp->d_name + 2);
(void) wcscpy(plain_file_name_p, wcs_buffer);
plain_file = GETNAME(plain_file_name, FIND_LENGTH);
plain_file->stat.is_file = true;
plain_file->stat.has_sccs = HAS_SCCS;
if(plain_file->prop) {
Property sprop = get_prop(plain_file->prop,sccs_prop);
if(sprop != NULL) {
if (sprop->body.sccs.file) {
goto try_pattern;
}
}
}
maybe_append_prop(plain_file, sccs_prop)->
body.sccs.file = file;
try_pattern:
MBSTOWCS(tmp_wcs_buffer, dp->d_name + 2);
if ((pattern != NULL) &&
amatch(tmp_wcs_buffer, pattern)) {
if (debug_level > 0) {
WCSTOMBS(mbs_buffer, pattern);
(void) printf(gettext("'%s: %s' due to %s expansion\n"),
line->body.line.target->
string_mb,
plain_file->string_mb,
mbs_buffer);
}
enter_dependency(line, plain_file, false);
result++;
}
}
}
(void) closedir(dir_fd);
return result;
}
static Name
enter_file_name(wchar_t *name_string, wchar_t *library)
{
wchar_t buffer[STRING_BUFFER_LENGTH];
String_rec lib_name;
Name name;
Property prop;
if (library == NULL) {
name = GETNAME(name_string, FIND_LENGTH);
name->stat.is_file = true;
return name;
}
INIT_STRING_FROM_STACK(lib_name, buffer);
append_string(library, &lib_name, FIND_LENGTH);
append_char((int) parenleft_char, &lib_name);
append_string(name_string, &lib_name, FIND_LENGTH);
append_char((int) parenright_char, &lib_name);
name = GETNAME(lib_name.buffer.start, FIND_LENGTH);
name->stat.is_file = true;
name->is_member = true;
prop = maybe_append_prop(name, member_prop);
prop->body.member.library = GETNAME(library, FIND_LENGTH);
prop->body.member.library->stat.is_file = true;
prop->body.member.entry = NULL;
prop->body.member.member = GETNAME(name_string, FIND_LENGTH);
prop->body.member.member->stat.is_file = true;
return name;
}
static Boolean
star_match(wchar_t *string, wchar_t *pattern)
{
int pattern_ch;
switch (*pattern) {
case 0:
return succeeded;
case bracketleft_char:
case question_char:
case asterisk_char:
while (*string) {
if (amatch(string++, pattern)) {
return succeeded;
}
}
break;
default:
pattern_ch = (int) *pattern++;
while (*string) {
if ((*string++ == pattern_ch) &&
amatch(string, pattern)) {
return succeeded;
}
}
break;
}
return failed;
}
static Boolean
amatch(wchar_t *string, wchar_t *pattern)
{
long lower_bound;
long string_ch;
long pattern_ch;
int k;
top:
for (; 1; pattern++, string++) {
lower_bound = 017777777777;
string_ch = *string;
switch (pattern_ch = *pattern) {
case bracketleft_char:
k = 0;
while ((pattern_ch = *++pattern) != 0) {
switch (pattern_ch) {
case bracketright_char:
if (!k) {
return failed;
}
string++;
pattern++;
goto top;
case hyphen_char:
k |= (lower_bound <= string_ch) &&
(string_ch <=
(pattern_ch = pattern[1]));
default:
if (string_ch ==
(lower_bound = pattern_ch)) {
k++;
}
}
}
return failed;
case asterisk_char:
return star_match(string, ++pattern);
case 0:
return BOOLEAN(!string_ch);
case question_char:
if (string_ch == 0) {
return failed;
}
break;
default:
if (pattern_ch != string_ch) {
return failed;
}
break;
}
}
}