bool CDFFDUseStruct::check_data()
{
	// Get values from the controls and validate them
	UpdateData();

	// Make sure name is given unless the container is a FOR (whence sub-elements are accessed via array index)
	if (name_.IsEmpty() && parent_type_ != CHexEditDoc::DF_FORV && parent_type_ != CHexEditDoc::DF_FORF)
	{
		TaskMessageBox("No Name", "Please enter a name for this element");
		ctl_name_.SetFocus();
		return false;
	}

	if (!name_.IsEmpty() && !valid_id(name_))
	{
		TaskMessageBox("Invalid STRUCT Name", "Please use alphanumeric characters (or "
						"underscores) and begin the name with an alphabetic character.");
		ctl_name_.SetFocus();
		return false;
	}
	if (name_.CompareNoCase("true") == 0 ||
		name_.CompareNoCase("false") == 0 ||
		name_.CompareNoCase("end") == 0 ||
		expr_eval::func_token(name_) != expr_eval::TOK_NONE)
	{
		TaskMessageBox("Reserved Name", name_ + " is reserved for internal use. Please choose another name.");
		ctl_name_.SetFocus();
		return false;
	}

	if (struct_.IsEmpty())
	{
		TaskMessageBox("No Defined Struct", "Please select a defined struct for this element");
		ctl_struct_.SetFocus();
		return false;
	}
	else if (!valid_id(struct_))
	{
		TaskMessageBox("Invalid Defined Struct Name", "Please use alphanumeric characters "
					  "(or underscore) and start with a alphabetic character.");
		ctl_name_.SetFocus();
		return false;
	}

	// We can only have an empty name if parent is FOR in which case there are no siblings
	ASSERT(!name_.IsEmpty() || pelt_->GetParent().GetNumChildren() == 1);

	// Check that the name is not the same as any siblings
	CXmlTree::CElt ee;

	// First find the actual element whose siblings we want to check (an IF takes the name of its child)
	for (ee = *pelt_; ee.GetParent().GetName() == "if" || ee.GetParent().GetName() == "jump"; ee = ee.GetParent())
		; // empty loop body

	// Check that older siblings don't have the same name
	for (ee--; !ee.IsEmpty(); ee--)
	{
		CXmlTree::CElt ee2;
		for (ee2 = ee; !ee2.IsEmpty() && (ee2.GetName() == "if" || ee2.GetName() == "jump"); ee2 = ee2.GetFirstChild())
			; // nothing here
		if (!ee2.IsEmpty() && ee2.GetAttr("name") == name_)
		{
			TaskMessageBox("Name in use", name_ + " has a sibling with the same name.\n\n"
				           "It is not be possible to differentiate between two elements "
			               "with the same name at the same level (eg, in expressions).");
			ctl_name_.SetFocus();
			return false;
		}
	}

	for (ee = *pelt_; ee.GetParent().GetName() == "if" || ee.GetParent().GetName() == "jump"; ee = ee.GetParent())
		; // empty loop body

	// Check that younger siblings don't have the same name
	for (++ee; !ee.IsEmpty(); ++ee)
	{
		CXmlTree::CElt ee2;
		for (ee2 = ee; !ee2.IsEmpty() && (ee2.GetName() == "if" || ee2.GetName() == "jump"); ee2 = ee2.GetFirstChild())
			; // nothing here
		if (!ee2.IsEmpty() && ee2.GetAttr("name") == name_)
		{
			TaskMessageBox("Name in use", name_ + " has a sibling with the same name.\n\n"
				           "It is not be possible to differentiate between two elements "
			               "with the same name at the same level (eg, in expressions).");
			ctl_name_.SetFocus();
			return false;
		}
	}

	return true;
}
Example #2
0
// Make a whole menu system that shows all the variables that can be accessed
// by an element in an expression.
// Returns a pointer to a CMenu that must be destroyed and freed, unless NULL
// is returned in which case no variables were found.
CMenu *make_var_menu_tree(const CXmlTree::CElt &current_elt, bool this_too /*=false*/, bool file_too /*=false*/)
{
	int item_no = 1;

	// Get sibling items
	CMenu *retval = make_menu(current_elt, item_no);

	// Add "this" if required
	if (this_too)
	{
		ASSERT(current_elt.GetName() != "if" && current_elt.GetName() != "switch");
		ASSERT(current_elt.GetNumChildren() <= 1);
		ASSERT(prev_defined.size() == 0);   // Make sure the list is cleared
		if (current_elt.GetNumChildren() > 0)
			add_menu_items(retval, item_no, current_elt.GetFirstChild(), _T("this"));
		else
			retval->AppendMenu(MF_ENABLED, item_no++, _T("this"));
		prev_defined.clear();
	}

	// Added in 3.5 - ability to use file values (cursor, mark, eof) in expressions
	if (file_too)
	{
		CMenu * submenu = new CMenu;
		submenu->CreatePopupMenu();

		submenu->AppendMenu(MF_ENABLED, item_no++, _T("cursor"));
		submenu->AppendMenu(MF_ENABLED, item_no++, _T("mark"));
		submenu->AppendMenu(MF_ENABLED, item_no++, _T("eof"));
		retval->AppendMenu(MF_POPUP, (UINT)submenu->m_hMenu, _T("From File"));
	}

	// Now check each ancestor in turn and add sub-menu (if not empty)
	CXmlTree::CElt ee;                  // Node of ancestor (starting with parent)
	int ii;                             // Keep track of which ancestor (1 = parent)
	for (ee = current_elt.GetParent(), ii = 1;
		 ee.GetName() != "binary_file_format";
		 ee = ee.GetParent(), ++ii )
	{
		CMenu *submenu = make_menu(ee, item_no);
		if (submenu->GetMenuItemCount() > 0)
		{
			// Add this menu as a submenu (popup)
			CString submenu_name;
			if (ii == 1)
				submenu_name = "Parent siblings";
			else if (ii == 2)
				submenu_name = "Grandparent siblings";
			else
				submenu_name.Format("Ancestor [%d] siblings", ii);

			retval->AppendMenu(MF_POPUP, (UINT)submenu->m_hMenu, submenu_name);
		}
		else
			submenu->DestroyMenu();
		delete submenu;
	}

	// If we added nothing just put a dummy (disabled) menu item in there
	if (retval->GetMenuItemCount() == 0)
		retval->AppendMenu(MF_GRAYED, -1, _T("No values available"));

	return retval;
}