473 lines
12 KiB
C
473 lines
12 KiB
C
/****************************************************************
|
|
* *
|
|
* Copyright 2001, 2011 Fidelity Information Services, Inc *
|
|
* *
|
|
* This source code contains the intellectual property *
|
|
* of its copyright holder(s), and is made available *
|
|
* under a license. If you do not know the terms of *
|
|
* the license, please stop and do not read further. *
|
|
* *
|
|
****************************************************************/
|
|
|
|
#include "mdef.h"
|
|
|
|
#include "gtm_string.h"
|
|
#include "gtm_dirent.h"
|
|
|
|
#include <errno.h>
|
|
#include "gtm_stat.h"
|
|
|
|
#include "io.h"
|
|
#include "iosp.h"
|
|
#include "parse_file.h"
|
|
#include "patcode.h"
|
|
#include "compiler.h"
|
|
#include "lv_val.h"
|
|
#include "stringpool.h"
|
|
#include "stp_parms.h"
|
|
#include "error.h"
|
|
#include "eintr_wrappers.h"
|
|
#include "op.h"
|
|
#include "zroutines.h"
|
|
#include "mvalconv.h"
|
|
#include "gtmctype.h"
|
|
#include "gdsroot.h"
|
|
#include "gtm_facility.h"
|
|
#include "fileinfo.h"
|
|
#include "gdsbt.h"
|
|
#include "gdsfhead.h"
|
|
#include "alias.h"
|
|
|
|
GBLREF symval *curr_symval;
|
|
GBLREF boolean_t gtm_utf8_mode;
|
|
GBLREF spdesc stringpool;
|
|
|
|
LITREF mval literal_null;
|
|
|
|
STATICFNDCL CONDITION_HANDLER(fnzsrch_ch);
|
|
STATICFNDCL CONDITION_HANDLER(dir_ch);
|
|
STATICFNDCL int pop_top(lv_val *src, mval *res);
|
|
|
|
void dir_srch(parse_blk *pfil);
|
|
|
|
error_def(ERR_ASSERT);
|
|
error_def(ERR_GTMASSERT);
|
|
error_def(ERR_GTMASSERT2);
|
|
error_def(ERR_GTMCHECK);
|
|
error_def(ERR_INVSTRLEN);
|
|
error_def(ERR_MEMORY);
|
|
error_def(ERR_STACKOFLOW);
|
|
|
|
int op_fnzsearch(mval *file, mint indx, mval *ret)
|
|
{
|
|
struct stat statbuf;
|
|
int stat_res;
|
|
parse_blk pblk;
|
|
plength *plen, pret;
|
|
char buf1[MAX_FBUFF + 1]; /* buffer to hold translated name */
|
|
mval sub;
|
|
mstr tn;
|
|
lv_val *ind_tmp;
|
|
DCL_THREADGBL_ACCESS;
|
|
|
|
SETUP_THREADGBL_ACCESS;
|
|
ESTABLISH_RET(fnzsrch_ch, -1);
|
|
TREF(fnzsearch_nullsubs_sav) = TREF(lv_null_subs);
|
|
TREF(lv_null_subs) = LVNULLSUBS_OK; /* $ZSearch processing depends on this */
|
|
MV_FORCE_STR(file);
|
|
if (file->str.len > MAX_FBUFF)
|
|
rts_error(VARLSTCNT(4) ERR_INVSTRLEN, 2, file->str.len, MAX_FBUFF);
|
|
MV_FORCE_MVAL(((mval *)TADR(fnzsearch_sub_mval)), indx);
|
|
TREF(fnzsearch_lv_vars) = op_srchindx(VARLSTCNT(2) TREF(zsearch_var), (mval *)TADR(fnzsearch_sub_mval));
|
|
if (TREF(fnzsearch_lv_vars))
|
|
{
|
|
assert((TREF(fnzsearch_lv_vars))->v.mvtype & MV_STR);
|
|
if ((file->str.len != (TREF(fnzsearch_lv_vars))->v.str.len)
|
|
|| memcmp(file->str.addr, (TREF(fnzsearch_lv_vars))->v.str.addr, file->str.len))
|
|
{
|
|
op_kill(TREF(fnzsearch_lv_vars));
|
|
TREF(fnzsearch_lv_vars) = NULL;
|
|
}
|
|
}
|
|
if (TREF(fnzsearch_lv_vars))
|
|
{
|
|
for (;;)
|
|
{
|
|
pret.p.pint = pop_top(TREF(fnzsearch_lv_vars), ret); /* get next element off the top */
|
|
if (!ret->str.len)
|
|
break;
|
|
memcpy(buf1, ret->str.addr, ret->str.len);
|
|
buf1[ret->str.len] = 0;
|
|
STAT_FILE(buf1, &statbuf, stat_res);
|
|
if (-1 == stat_res)
|
|
{
|
|
if (errno == ENOENT)
|
|
continue;
|
|
rts_error(VARLSTCNT(1) errno);
|
|
}
|
|
break;
|
|
}
|
|
} else
|
|
{
|
|
memset(&pblk, 0, SIZEOF(pblk));
|
|
pblk.buffer = buf1;
|
|
pblk.buff_size = MAX_FBUFF;
|
|
if (!(parse_file(&file->str, &pblk) & 1))
|
|
{
|
|
ret->mvtype = MV_STR;
|
|
ret->str.len = 0;
|
|
} else
|
|
{
|
|
assert(!TREF(fnzsearch_lv_vars));
|
|
buf1[pblk.b_esl] = 0;
|
|
/* establish new search context */
|
|
TREF(fnzsearch_lv_vars) = op_putindx(VARLSTCNT(2) TREF(zsearch_var), TADR(fnzsearch_sub_mval));
|
|
(TREF(fnzsearch_lv_vars))->v = *file; /* zsearch_var(indx)=original spec */
|
|
if (!(pblk.fnb & F_WILD))
|
|
{
|
|
sub.mvtype = MV_STR;
|
|
sub.str.len = pblk.b_esl;
|
|
sub.str.addr = buf1;
|
|
s2pool(&sub.str);
|
|
ind_tmp = op_putindx(VARLSTCNT(2) TREF(fnzsearch_lv_vars), &sub);
|
|
ind_tmp->v.mvtype = MV_STR; ind_tmp->v.str.len = 0;
|
|
plen = (plength *)&ind_tmp->v.m[1];
|
|
plen->p.pblk.b_esl = pblk.b_esl;
|
|
plen->p.pblk.b_dir = pblk.b_dir;
|
|
plen->p.pblk.b_name = pblk.b_name;
|
|
plen->p.pblk.b_ext = pblk.b_ext;
|
|
} else
|
|
dir_srch(&pblk);
|
|
for (;;)
|
|
{
|
|
pret.p.pint = pop_top(TREF(fnzsearch_lv_vars), ret); /* get next element off the top */
|
|
if (!ret->str.len)
|
|
break;
|
|
memcpy(buf1, ret->str.addr, ret->str.len);
|
|
buf1[ret->str.len] = 0;
|
|
STAT_FILE(buf1, &statbuf, stat_res);
|
|
if (-1 == stat_res)
|
|
{
|
|
if (errno == ENOENT)
|
|
continue;
|
|
rts_error(VARLSTCNT(1) errno);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
assert((0 == ret->str.len) || (pret.p.pblk.b_esl == ret->str.len));
|
|
TREF(lv_null_subs) = TREF(fnzsearch_nullsubs_sav);
|
|
REVERT;
|
|
return pret.p.pint;
|
|
}
|
|
|
|
void dir_srch(parse_blk *pfil)
|
|
{
|
|
struct stat statbuf;
|
|
int stat_res;
|
|
lv_val *dir1, *dir2, *tmp;
|
|
mstr tn;
|
|
short p2_len;
|
|
char filb[MAX_FBUFF + 1], patb[SIZEOF(ptstr)], *c, *lastd, *top, *p2, *c1, ch;
|
|
mval pat_mval, sub, compare;
|
|
boolean_t wildname, seen_wd;
|
|
struct dirent *dent;
|
|
DIR *dp;
|
|
plength *plen;
|
|
int closedir_res;
|
|
DCL_THREADGBL_ACCESS;
|
|
|
|
SETUP_THREADGBL_ACCESS;
|
|
op_kill(TREF(zsearch_dir1));
|
|
op_kill(TREF(zsearch_dir2));
|
|
if (!pfil->b_name)
|
|
return; /* nothing to search for */
|
|
ESTABLISH(dir_ch);
|
|
pat_mval.mvtype = MV_STR;
|
|
pat_mval.str.addr = patb; /* patb should be SIZEOF(ptstr.buff) but instead is SIZEOF(ptstr) since the C compiler
|
|
* complains about the former and the latter is just 4 bytes more */
|
|
pat_mval.str.len = 0;
|
|
sub.mvtype = MV_STR;
|
|
sub.str.len = 0;
|
|
compare.mvtype = MV_STR;
|
|
compare.str.len = 0;
|
|
wildname = (pfil->fnb & F_WILD_NAME) != 0;
|
|
dir1 = TREF(zsearch_dir1);
|
|
dir2 = TREF(zsearch_dir2);
|
|
if (pfil->fnb & F_WILD_DIR)
|
|
{
|
|
seen_wd = FALSE;
|
|
for (c = pfil->l_dir, lastd = c, top = c + pfil->b_dir; c < top;)
|
|
{
|
|
ch = *c++;
|
|
if (ch == '/') /* note the start of each directory segment */
|
|
{
|
|
if (seen_wd)
|
|
break;
|
|
lastd = c;
|
|
}
|
|
if (ch == '?' || ch == '*')
|
|
seen_wd = TRUE;
|
|
}
|
|
assert(c <= top);
|
|
sub.str.addr = pfil->l_dir;
|
|
sub.str.len = INTCAST(lastd - sub.str.addr);
|
|
tmp = op_putindx(VARLSTCNT(2) dir1, &sub);
|
|
tmp->v.mvtype = MV_STR; tmp->v.str.len = 0;
|
|
for (;;)
|
|
{
|
|
tn.addr = lastd; /* wildcard segment */
|
|
tn.len = INTCAST(c - lastd - 1);
|
|
lastd = c;
|
|
genpat(&tn, &pat_mval);
|
|
seen_wd = FALSE;
|
|
p2 = c - 1;
|
|
for (; c < top;)
|
|
{
|
|
ch = *c++;
|
|
if (ch == '/') /* note the start of each directory segment */
|
|
{
|
|
if (seen_wd)
|
|
break;
|
|
lastd = c;
|
|
}
|
|
if (ch == '?' || ch == '*')
|
|
seen_wd = TRUE;
|
|
}
|
|
p2_len = lastd - p2; /* length of non-wild segment after wild section */
|
|
for (;;)
|
|
{
|
|
pop_top(dir1, &sub); /* get next item off the top */
|
|
if (!sub.str.len)
|
|
break;
|
|
memcpy(filb, sub.str.addr, sub.str.len);
|
|
filb[sub.str.len] = 0;
|
|
sub.str.addr = filb;
|
|
dp = OPENDIR(filb);
|
|
if (!dp)
|
|
continue;
|
|
while (READDIR(dp, dent))
|
|
{
|
|
compare.str.addr = &dent->d_name[0];
|
|
compare.str.len = STRLEN(&dent->d_name[0]);
|
|
UNICODE_ONLY(
|
|
if (gtm_utf8_mode)
|
|
compare.mvtype &= ~MV_UTF_LEN; /* to force "char_len" to be recomputed
|
|
* in do_pattern */
|
|
)
|
|
assert(compare.str.len);
|
|
if (('.' == dent->d_name[0])
|
|
&& ((1 == compare.str.len) || ((2 == compare.str.len) && ('.' == dent->d_name[1]))))
|
|
continue; /* don't want to read . and .. */
|
|
if (compare.str.len + sub.str.len + p2_len > MAX_FBUFF)
|
|
continue;
|
|
if (do_pattern(&compare, &pat_mval))
|
|
{ /* got a hit */
|
|
ENSURE_STP_FREE_SPACE(compare.str.len + sub.str.len + p2_len + 1);
|
|
/* concatenate directory and name */
|
|
c1 = (char *)stringpool.free;
|
|
tn = sub.str;
|
|
s2pool(&tn);
|
|
tn = compare.str;
|
|
s2pool(&tn);
|
|
tn.addr = p2;
|
|
tn.len = p2_len;
|
|
s2pool(&tn);
|
|
*stringpool.free++ = 0;
|
|
compare.str.addr = c1;
|
|
compare.str.len += sub.str.len + p2_len;
|
|
STAT_FILE(compare.str.addr, &statbuf, stat_res);
|
|
if (-1 == stat_res)
|
|
continue;
|
|
if (!(statbuf.st_mode & S_IFDIR))
|
|
continue;
|
|
/* put in results tree */
|
|
tmp = op_putindx(VARLSTCNT(2) dir2, &compare);
|
|
tmp->v.mvtype = MV_STR;
|
|
tmp->v.str.len = 0;
|
|
}
|
|
}
|
|
CLOSEDIR(dp, closedir_res);
|
|
}
|
|
tmp = dir1; dir1 = dir2; dir2 = tmp;
|
|
if (c >= top)
|
|
break;
|
|
}
|
|
} else
|
|
{
|
|
sub.str.addr = pfil->l_dir;
|
|
sub.str.len = pfil->b_dir;
|
|
tmp = op_putindx(VARLSTCNT(2) dir1, &sub);
|
|
tmp->v.mvtype = MV_STR; tmp->v.str.len = 0;
|
|
}
|
|
if (wildname)
|
|
{
|
|
tn.addr = pfil->l_name;
|
|
tn.len = pfil->b_name + pfil->b_ext;
|
|
genpat(&tn, &pat_mval);
|
|
}
|
|
for (;;)
|
|
{
|
|
pop_top(dir1, &sub); /* get next item off the top */
|
|
if (!sub.str.len)
|
|
break;
|
|
if (wildname)
|
|
{
|
|
memcpy(filb, sub.str.addr, sub.str.len);
|
|
filb[sub.str.len] = 0;
|
|
sub.str.addr = filb;
|
|
dp = OPENDIR(filb);
|
|
if (!dp)
|
|
continue;
|
|
while (READDIR(dp, dent))
|
|
{
|
|
compare.str.addr = &dent->d_name[0];
|
|
compare.str.len = STRLEN(&dent->d_name[0]);
|
|
UNICODE_ONLY(
|
|
if (gtm_utf8_mode)
|
|
compare.mvtype &= ~MV_UTF_LEN;/* force "char_len" to be recomputed in do_pattern */
|
|
)
|
|
if (('.' == dent->d_name[0])
|
|
&& ((1 == compare.str.len) || ((2 == compare.str.len) && ('.' == dent->d_name[1]))))
|
|
{
|
|
continue; /* don't want to read . and .. */
|
|
}
|
|
if (compare.str.len + sub.str.len > MAX_FBUFF)
|
|
continue;
|
|
if (do_pattern(&compare, &pat_mval))
|
|
{ /* got a hit */
|
|
ENSURE_STP_FREE_SPACE(compare.str.len + sub.str.len);
|
|
/* concatenate directory and name */
|
|
c = (char *)stringpool.free;
|
|
tn = sub.str;
|
|
s2pool(&tn);
|
|
tn = compare.str;
|
|
s2pool(&tn);
|
|
compare.str.addr = c;
|
|
compare.str.len += sub.str.len;
|
|
/* put in results tree */
|
|
tmp = op_putindx(VARLSTCNT(2) TREF(fnzsearch_lv_vars), &compare);
|
|
tmp->v.mvtype = MV_STR;
|
|
tmp->v.str.len = 0;
|
|
plen = (plength *)&tmp->v.m[1];
|
|
plen->p.pblk.b_esl = compare.str.len;
|
|
plen->p.pblk.b_dir = sub.str.len;
|
|
for (c = &compare.str.addr[sub.str.len], c1 = top = &compare.str.addr[compare.str.len];
|
|
c < top;)
|
|
{
|
|
if (*c++ != '.')
|
|
break;
|
|
}
|
|
for (; c < top;)
|
|
{
|
|
if (*c++ == '.')
|
|
c1 = c - 1;
|
|
}
|
|
plen->p.pblk.b_ext = top - c1;
|
|
plen->p.pblk.b_name = plen->p.pblk.b_esl - plen->p.pblk.b_dir - plen->p.pblk.b_ext;
|
|
}
|
|
}
|
|
CLOSEDIR(dp, closedir_res);
|
|
} else
|
|
{
|
|
assert(pfil->fnb & F_WILD_DIR);
|
|
compare.str.addr = pfil->l_name;
|
|
compare.str.len = pfil->b_name + pfil->b_ext;
|
|
if (compare.str.len + sub.str.len > MAX_FBUFF)
|
|
continue;
|
|
memcpy(filb, sub.str.addr, sub.str.len);
|
|
filb[sub.str.len] = 0;
|
|
sub.str.addr = filb;
|
|
ENSURE_STP_FREE_SPACE(compare.str.len + sub.str.len);
|
|
/* concatenate directory and name */
|
|
c1 = (char *)stringpool.free;
|
|
tn = sub.str;
|
|
s2pool(&tn);
|
|
tn = compare.str;
|
|
s2pool(&tn);
|
|
compare.str.addr = c1;
|
|
compare.str.len += sub.str.len;
|
|
/* put in results tree */
|
|
tmp = op_putindx(VARLSTCNT(2) TREF(fnzsearch_lv_vars), &compare);
|
|
tmp->v.mvtype = MV_STR; tmp->v.str.len = 0;
|
|
plen = (plength *)&tmp->v.m[1];
|
|
plen->p.pblk.b_esl = compare.str.len;
|
|
plen->p.pblk.b_dir = sub.str.len;
|
|
plen->p.pblk.b_name = pfil->b_name;
|
|
plen->p.pblk.b_ext = pfil->b_ext;
|
|
}
|
|
}
|
|
op_kill(TREF(zsearch_dir1));
|
|
op_kill(TREF(zsearch_dir2));
|
|
REVERT;
|
|
}
|
|
|
|
STATICFNDEF CONDITION_HANDLER(fnzsrch_ch)
|
|
{
|
|
int dummy1, dummy2;
|
|
|
|
START_CH;
|
|
TREF(lv_null_subs) = TREF(fnzsearch_nullsubs_sav);
|
|
NEXTCH;
|
|
}
|
|
|
|
STATICFNDEF CONDITION_HANDLER(dir_ch)
|
|
{
|
|
int dummy1, dummy2;
|
|
|
|
START_CH;
|
|
if (DUMP)
|
|
{
|
|
NEXTCH;
|
|
}
|
|
op_kill(TREF(zsearch_dir1));
|
|
op_kill(TREF(zsearch_dir2));
|
|
op_kill(TREF(fnzsearch_lv_vars));
|
|
TREF(fnzsearch_lv_vars) = op_putindx(VARLSTCNT(2) TREF(zsearch_var), TADR(fnzsearch_sub_mval));
|
|
(TREF(fnzsearch_lv_vars))->v.mvtype = MV_STR;
|
|
(TREF(fnzsearch_lv_vars))->v.str.len = 0;
|
|
UNWIND(dummy1, dummy2);
|
|
}
|
|
|
|
void zsrch_clr(int indx)
|
|
{
|
|
lv_val *tmp;
|
|
mval x;
|
|
DCL_THREADGBL_ACCESS;
|
|
|
|
SETUP_THREADGBL_ACCESS;
|
|
MV_FORCE_MVAL(&x, indx);
|
|
op_kill(TREF(zsearch_dir1));
|
|
op_kill(TREF(zsearch_dir2));
|
|
tmp = op_srchindx(VARLSTCNT(2) TREF(zsearch_var), &x);
|
|
op_kill(tmp);
|
|
}
|
|
|
|
/* pop_top() - routine scans the specified local variable (in this case, special locals used by $ZSEARCH), taking the top
|
|
* subscript out of the array, and putting it in the result mval. Subscripts longer than the parse_file() maximum are ignored.
|
|
*/
|
|
STATICFNDEF int pop_top(lv_val *src, mval *res)
|
|
{
|
|
lv_val *tmp;
|
|
plength pret;
|
|
|
|
for (;;)
|
|
{ /* get next element off the top */
|
|
op_fnorder(src, (mval *)&literal_null, res);
|
|
if (!res->str.len)
|
|
{
|
|
pret.p.pint = 0;
|
|
op_kill(src);
|
|
break;
|
|
}
|
|
tmp = op_getindx(VARLSTCNT(2) src, res);
|
|
pret.p.pint = tmp->v.m[1];
|
|
op_kill(tmp); /* remove this element from tree */
|
|
if (res->str.len > MAX_FBUFF)
|
|
continue;
|
|
break;
|
|
}
|
|
return pret.p.pint;
|
|
}
|