static CONDITION_HANDLER(dir_ch) { int dummy1, dummy2; error_def(ERR_ASSERT); error_def(ERR_GTMASSERT); error_def(ERR_GTMCHECK); error_def(ERR_STACKOFLOW); START_CH; if (DUMP) { NEXTCH; } op_kill(zsrch_dir1); op_kill(zsrch_dir2); op_kill(ind_var); ind_var = op_putindx(VARLSTCNT(2) zsrch_var, &ind_val); ind_var->v.mvtype = MV_STR; ind_var->v.str.len = 0; UNWIND(dummy1, dummy2); }
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; error_def(ERR_INVSTRLEN); 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(&ind_val, indx); ind_var = op_srchindx(VARLSTCNT(2) zsrch_var, &ind_val); if (ind_var) { assert(ind_var->v.mvtype & MV_STR); if (file->str.len != ind_var->v.str.len || memcmp(file->str.addr, ind_var->v.str.addr, file->str.len)) { op_kill(ind_var); ind_var = (lv_val*) 0; } } if (ind_var) { for (;;) { pret.p.pint = pop_top(ind_var, 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(!ind_var); buf1[pblk.b_esl] = 0; /* establish new search context */ ind_var = op_putindx(VARLSTCNT(2) zsrch_var, &ind_val); ind_var->v = *file; /* zsrch_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) ind_var, &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(ind_var, 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(pret.p.pblk.b_esl == ret->str.len); 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; bool wildname, seen_wd; struct dirent *dent; DIR *dp; plength *plen; int closedir_res; op_kill(zsrch_dir1); op_kill(zsrch_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 = zsrch_dir1; dir2 = zsrch_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 = 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 = 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]); assert(compare.str.len); if ( dent->d_name[0] == '.' && (compare.str.len == 1 || (compare.str.len == 2 && 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 */ if (stringpool.free + compare.str.len + sub.str.len + p2_len + 1 > stringpool.top) stp_gcol(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]); if ( dent->d_name[0] == '.' && (compare.str.len == 1 || (compare.str.len == 2 && 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 */ if (stringpool.free + compare.str.len + sub.str.len > stringpool.top) stp_gcol(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) ind_var, &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; if (stringpool.free + compare.str.len + sub.str.len > stringpool.top) stp_gcol(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) ind_var, &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(zsrch_dir1); op_kill(zsrch_dir2); REVERT; }
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; }
void op_merge(void) { boolean_t found, check_for_null_subs, is_base_var; lv_val *dst_lv; mval *mkey, *value, *subsc; int org_glvn1_keysz, org_glvn2_keysz, delta2, dollardata_src, dollardata_dst, sbs_depth; unsigned char *ptr, *ptr2; unsigned char buff[MAX_ZWR_KEY_SZ]; unsigned char nullcoll_src, nullcoll_dst; zshow_out output; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; assert(MAX_STRLEN >= MAX_ZWR_KEY_SZ); assert ((merge_args == (MARG1_LCL | MARG2_LCL)) || (merge_args == (MARG1_LCL | MARG2_GBL)) || (merge_args == (MARG1_GBL | MARG2_LCL)) || (merge_args == (MARG1_GBL | MARG2_GBL))); assert(!lvzwrite_block || 0 == lvzwrite_block->curr_subsc); /* Need to protect value from stpgcol */ PUSH_MV_STENT(MVST_MVAL); value = &mv_chain->mv_st_cont.mvs_mval; value->mvtype = 0; /* initialize mval in the M-stack in case stp_gcol gets called before value gets initialized below */ if (MARG2_IS_GBL(merge_args)) { /* Need to protect mkey returned from gvcst_queryget from stpgcol */ PUSH_MV_STENT(MVST_MVAL); mkey = &mv_chain->mv_st_cont.mvs_mval; mkey->mvtype = 0; /* initialize mval in M-stack in case stp_gcol gets called before mkey gets initialized below */ gvname_env_restore(mglvnp->gblp[IND2]); /* now $DATA will be done for gvn2. op_gvdata input parameters are set in the form of some GBLREF */ op_gvdata(value); dollardata_src = MV_FORCE_INT(value); if (0 == dollardata_src) { /* nothing in source global */ UNDO_ACTIVE_LV; POP_MV_STENT(); /* value */ POP_MV_STENT(); /* mkey */ if (MARG1_IS_GBL(merge_args)) gvname_env_restore(mglvnp->gblp[IND1]); /* store destination as naked indicator in gv_currkey */ merge_args = 0; /* Must reset to zero to reuse the Global */ return; } if (NULL == TREF(gv_mergekey2)) { /* We need to initialize gvn2 (right hand side). */ GVKEY_INIT(TREF(gv_mergekey2), DBKEYSIZE(MAX_KEY_SZ)); } org_glvn1_keysz = mglvnp->gblp[IND1]->s_gv_currkey->end + 1; org_glvn2_keysz = gv_currkey->end + 1; (TREF(gv_mergekey2))->end = gv_currkey->end; (TREF(gv_mergekey2))->prev = gv_currkey->prev; memcpy((TREF(gv_mergekey2))->base, gv_currkey->base, gv_currkey->end + 1); if (MARG1_IS_GBL(merge_args)) { /*==================== MERGE ^gvn1=^gvn2 =====================*/ if (mglvnp->gblp[IND2]->s_gv_target->nct != mglvnp->gblp[IND1]->s_gv_target->nct) rts_error(VARLSTCNT(1) ERR_NCTCOLLDIFF); /* if self merge then NOOP*/ if (!merge_desc_check()) /* will not proceed if one is descendant of another */ { gvname_env_restore(mglvnp->gblp[IND1]); /* store destination as naked indicator in gv_currkey */ POP_MV_STENT(); /* value */ merge_args = 0; /* Must reset to zero to reuse the Global */ return; } nullcoll_src = mglvnp->gblp[IND2]->s_gv_cur_region->std_null_coll; nullcoll_dst = mglvnp->gblp[IND1]->s_gv_cur_region->std_null_coll; if (1 == dollardata_src || 11 == dollardata_src) { found = op_gvget(value); /* value of ^glvn2 */ if (found) { /* SET ^gvn1=^gvn2 */ gvname_env_restore(mglvnp->gblp[IND1]); op_gvput(value); /* Note: If ^gvn1's null_sub=ALLOWEXISTING and say ^gvn1("")=^gvn, * this will give NULL_SUBC error */ } } check_for_null_subs = (NEVER != mglvnp->gblp[IND2]->s_gv_cur_region->null_subs) && (ALWAYS != mglvnp->gblp[IND1]->s_gv_cur_region->null_subs); /* Traverse descendant of ^gvn2 and copy into ^gvn1 */ for (; ;) { if (outofband) { gvname_env_restore(mglvnp->gblp[IND1]); /* naked indicator is restored into gv_currkey */ outofband_action(FALSE); } /* Restore last key under ^gvn2 we worked */ gvname_env_restore(mglvnp->gblp[IND2]); assert(0 == gv_currkey->base[gv_currkey->end - 1] && 0 == gv_currkey->base[gv_currkey->end]); /* following is an attempt to find immidiate right sibling */ gv_currkey->base[gv_currkey->end] = 1; gv_currkey->base[gv_currkey->end + 1] = 0; gv_currkey->base[gv_currkey->end + 2] = 0; gv_currkey->end += 2; /* Do atomic $QUERY and $GET of current glvn2: * mkey is a mstr which contains $QUERY result in database format (So no conversion necessary) * value is a mstr which contains $GET result */ if (!op_gvqueryget(mkey, value)) break; assert(MV_IS_STRING(mkey)); if (mkey->str.len < org_glvn2_keysz) break; if (0 != *((unsigned char *)mkey->str.addr + (TREF(gv_mergekey2))->end - 1) || memcmp(mkey->str.addr, (TREF(gv_mergekey2))->base, (TREF(gv_mergekey2))->end - 1)) break; /* mkey is not under the sub-tree */ delta2 = mkey->str.len - org_glvn2_keysz; /* length increase of source key */ assert (0 < delta2); /* Save the new source key for next iteration */ memcpy(mglvnp->gblp[IND2]->s_gv_currkey->base + org_glvn2_keysz - 2, mkey->str.addr + org_glvn2_keysz - 2, delta2 + 2); mglvnp->gblp[IND2]->s_gv_currkey->end = mkey->str.len - 1; /* Create the destination key for this iteration (under ^glvn1) */ gvname_env_restore(mglvnp->gblp[IND1]); if (gv_cur_region->max_key_size < org_glvn1_keysz + delta2) ISSUE_GVSUBOFLOW_ERROR(gv_currkey); assert(gv_currkey->end == org_glvn1_keysz - 1); memcpy(gv_currkey->base + org_glvn1_keysz - 2, mkey->str.addr + org_glvn2_keysz - 2, delta2 + 2); gv_currkey->end = org_glvn1_keysz + delta2 - 1; if (nullcoll_src != nullcoll_dst) { if (0 == nullcoll_dst) { /* Standard to GTM null subscript conversion*/ STD2GTMNULLCOLL((unsigned char *)gv_currkey->base + org_glvn1_keysz - 1, delta2 - 1); } else { /* GTM to standard null subscript conversion */ GTM2STDNULLCOLL((unsigned char *)gv_currkey->base + org_glvn1_keysz - 1, delta2 - 1); } } /* check null subscripts in destination key, note that we have already restored, destination global * and curresponding region, key information */ if (check_for_null_subs) { ptr2 = gv_currkey->base + gv_currkey->end - 1; for (ptr = gv_currkey->base + org_glvn1_keysz - 2; ptr < ptr2; ) { if (KEY_DELIMITER == *ptr++ && KEY_DELIMITER == *(ptr + 1) && (0 == gv_cur_region->std_null_coll ? (STR_SUB_PREFIX == *ptr) : (SUBSCRIPT_STDCOL_NULL == *ptr))) /* Note: For sgnl_gvnulsubsc/rts_error * we do not restore proper naked indicator. * The standard states that the effect of a MERGE command * on the naked indicator is that the naked indicator will be changed * as if a specific SET command would have been executed. * The standard also states that the effect on the naked indicator * will only take be visible after the MERGE command has completed. * So, if there is an error during the execution of a MERGE command, * the standard allows the naked indicator to reflect any intermediate * state. This provision was made intentionally, otherwise it would * have become nearly impossible to create a fully standard * implementation. : From Ed de Moel : 2/1/2 */ sgnl_gvnulsubsc(); } } /* Now put value of ^glvn2 descendant into corresponding descendant under ^glvn1 */ op_gvput(value); } gvname_env_restore(mglvnp->gblp[IND1]); /* store destination as naked indicator in gv_currkey */ } else { /*==================== MERGE lvn1=^gvn2 =====================*/ assert(MARG1_IS_LCL(merge_args)); assert(mglvnp->lclp[IND1]); /* Need to protect subsc created from global variable subscripts from stpgcol */ PUSH_MV_STENT(MVST_MVAL); subsc = &mv_chain->mv_st_cont.mvs_mval; /* Restore ^gvn2 we will work */ gvname_env_save(mglvnp->gblp[IND2]); if (1 == dollardata_src || 11 == dollardata_src) { /* SET lvn1=^gvn2 */ found = op_gvget(value); if (found) mglvnp->lclp[IND1]->v = *value; } for (; ;) { if (outofband) { gvname_env_restore(mglvnp->gblp[IND2]); /* naked indicator is restored into gv_currkey */ outofband_action(FALSE); } assert(0 == gv_currkey->base[gv_currkey->end - 1] && 0 == gv_currkey->base[gv_currkey->end]); /* following is an attempt to find immidiate right sibling */ gv_currkey->base[gv_currkey->end] = 1; gv_currkey->base[gv_currkey->end + 1] = 0; gv_currkey->base[gv_currkey->end + 2] = 0; gv_currkey->end += 2; /* Do $QUERY and $GET of current glvn2. Result will be in mkey and value respectively. * mkey->str contains data as database format. So no conversion necessary */ if (!op_gvqueryget(mkey, value)) break; if (mkey->str.len < (TREF(gv_mergekey2))->end + 1) break; ptr = (unsigned char *)mkey->str.addr + (TREF(gv_mergekey2))->end - 1; if (0 != *ptr || memcmp(mkey->str.addr, (TREF(gv_mergekey2))->base, (TREF(gv_mergekey2))->end - 1)) break; assert(MV_IS_STRING(mkey)); delta2 = mkey->str.len - org_glvn2_keysz; /* length increase of key */ assert (0 < delta2); /* Create next key for ^glvn2 */ memcpy(gv_currkey->base + org_glvn2_keysz - 2, mkey->str.addr + org_glvn2_keysz - 2, delta2 + 2); gv_currkey->end = mkey->str.len - 1; /* Now add subscripts to create the entire key */ dst_lv = mglvnp->lclp[IND1]; is_base_var = LV_IS_BASE_VAR(dst_lv); ptr = (unsigned char *)gv_currkey->base + org_glvn2_keysz - 1; assert(*ptr); do { LV_SBS_DEPTH(dst_lv, is_base_var, sbs_depth); if (MAX_LVSUBSCRIPTS <= sbs_depth) rts_error(VARLSTCNT(3) ERR_MERGEINCOMPL, 0, ERR_MAXNRSUBSCRIPTS); ptr2 = gvsub2str(ptr, buff, FALSE); subsc->mvtype = MV_STR; subsc->str.addr = (char *)buff; subsc->str.len = INTCAST(ptr2 - buff); s2pool(&subsc->str); dst_lv = op_putindx(VARLSTCNT(2) dst_lv, subsc); while (*ptr++); /* skip to start of next subscript */ is_base_var = FALSE; } while (*ptr); /* We created the key. Pre-process the node in case a container is being replaced, * then assign the value directly. Note there is no need to worry about MV_ALIASCONT * propagation since the source in this case is a global var. */ DECR_AC_REF(dst_lv, TRUE); dst_lv->v = *value; } gvname_env_restore(mglvnp->gblp[IND2]); /* naked indicator is restored into gv_currkey */ POP_MV_STENT(); /* subsc */ } POP_MV_STENT(); /* mkey */ } else { /* source is local */ op_fndata(mglvnp->lclp[IND2], value); dollardata_src = MV_FORCE_INT(value); if (0 == dollardata_src) { UNDO_ACTIVE_LV; POP_MV_STENT(); /* value */ if (MARG1_IS_GBL(merge_args)) gvname_env_restore(mglvnp->gblp[IND1]); /* store destination as naked indicator in gv_currkey */ merge_args = 0; /* Must reset to zero to reuse the Global */ return; } /* not memsetting output to 0 here can cause garbage value of output.out_var.lv.child which in turn can * cause a premature return from lvzwr_var resulting in op_merge() returning without having done the merge. */ memset(&output, 0, SIZEOF(output)); if (MARG1_IS_LCL(merge_args)) { /*==================== MERGE lvn1=lvn2 =====================*/ assert(mglvnp->lclp[IND1]); /* if self merge then NOOP */ if (!merge_desc_check()) /* will not proceed if one is descendant of another */ { POP_MV_STENT(); /* value */ merge_args = 0; /* Must reset to zero to reuse the Global */ return; } output.buff = (char *)buff; output.ptr = output.buff; output.out_var.lv.lvar = mglvnp->lclp[IND1]; zwr_output = &output; lvzwr_init(zwr_patrn_mident, &mglvnp->lclp[IND2]->v); lvzwr_arg(ZWRITE_ASTERISK, 0, 0); lvzwr_var(mglvnp->lclp[IND2], 0); /* assert that destination got all data of the source and its descendants */ DEBUG_ONLY(op_fndata(mglvnp->lclp[IND1], value)); DEBUG_ONLY(dollardata_dst = MV_FORCE_INT(value)); assert((dollardata_src & dollardata_dst) == dollardata_src); } else { /*==================== MERGE ^gvn1=lvn2 =====================*/ assert(MARG1_IS_GBL(merge_args) && MARG2_IS_LCL(merge_args)); gvname_env_save(mglvnp->gblp[IND1]); output.buff = (char *)buff; output.ptr = output.buff; output.out_var.gv.end = gv_currkey->end; output.out_var.gv.prev = gv_currkey->prev; zwr_output = &output; lvzwr_init(zwr_patrn_mident, &mglvnp->lclp[IND2]->v); lvzwr_arg(ZWRITE_ASTERISK, 0, 0); lvzwr_var(mglvnp->lclp[IND2], 0); gvname_env_restore(mglvnp->gblp[IND1]); /* store destination as naked indicator in gv_currkey */ } } POP_MV_STENT(); /* value */ merge_args = 0; /* Must reset to zero to reuse the Global */ }