int cil_gen_macro(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
{
	int rc = SEPOL_ERR;
	char *key = NULL;
	struct cil_macro *macro = NULL;
	struct cil_tree_node *macro_content = NULL;
	enum cil_syntax syntax[] = {
		CIL_SYN_STRING,
		CIL_SYN_STRING,
		CIL_SYN_LIST | CIL_SYN_EMPTY_LIST,
		CIL_SYN_N_LISTS | CIL_SYN_END,
		CIL_SYN_END
	};
	int syntax_len = sizeof(syntax)/ sizeof(*syntax);

	if (db == NULL || parse_current == NULL || ast_node == NULL) {
		goto exit;
	}

	rc =__cil_verify_syntax(parse_current, syntax, syntax_len);
	if (rc != SEPOL_OK) {
		goto exit;
	}

	cil_macro_init(&macro);

	key = parse_current->next->data;

	struct cil_tree_node *current_item = parse_current->next->next->cl_head;
	while (current_item != NULL) {
		enum cil_syntax param_syntax[] = {
			CIL_SYN_STRING,
			CIL_SYN_STRING,
			CIL_SYN_END
		};
		int param_syntax_len = sizeof(param_syntax)/sizeof(*param_syntax);
		char *kind = NULL;
		struct cil_param *param = NULL;

		rc =__cil_verify_syntax(current_item->cl_head, param_syntax, param_syntax_len);
		if (rc != SEPOL_OK) {
			goto exit;
		}

		if (macro->params == NULL) {
			cil_list_init(&macro->params, CIL_LIST_ITEM);
		}

		kind = current_item->cl_head->data;
		cil_param_init(&param);

		if (kind == CIL_KEY_TYPE) {
			param->flavor = CIL_TYPE;
		} else if (kind == CIL_KEY_ROLE) {
			param->flavor = CIL_ROLE;
		} else if (kind == CIL_KEY_USER) {
			param->flavor = CIL_USER;
		} else if (kind == CIL_KEY_SENSITIVITY) {
			param->flavor = CIL_SENS;
		} else if (kind == CIL_KEY_CATEGORY) {
			param->flavor = CIL_CAT;
		} else if (kind == CIL_KEY_CATSET) {
			param->flavor = CIL_CATSET;
		} else if (kind == CIL_KEY_LEVEL) {
			param->flavor = CIL_LEVEL;
		} else if (kind == CIL_KEY_LEVELRANGE) {
			param->flavor = CIL_LEVELRANGE;
		} else if (kind == CIL_KEY_CLASS) {
			param->flavor = CIL_CLASS;
		} else if (kind == CIL_KEY_IPADDR) {
			param->flavor = CIL_IPADDR;
		} else if (kind == CIL_KEY_MAP_CLASS) {
			param->flavor = CIL_MAP_CLASS;
		} else if (kind == CIL_KEY_CLASSPERMISSION) {
			param->flavor = CIL_CLASSPERMISSION;
		} else if (kind == CIL_KEY_BOOL) {
			param->flavor = CIL_BOOL;
		} else if (kind == CIL_KEY_STRING) {
			param->flavor = CIL_NAME;
		} else if (kind == CIL_KEY_NAME) {
			param->flavor = CIL_NAME;
		} else {
			cil_log(CIL_ERR, "The kind %s is not allowed as a parameter\n",kind);
			cil_destroy_param(param);
			goto exit;
		}

		param->str =  current_item->cl_head->next->data;

		rc = cil_verify_name(param->str, param->flavor);
		if (rc != SEPOL_OK) {
			cil_destroy_param(param);
			goto exit;
		}

		//walk current list and check for duplicate parameters
		struct cil_list_item *curr_param;
		cil_list_for_each(curr_param, macro->params) {
			if (param->str == ((struct cil_param*)curr_param->data)->str) {
				cil_log(CIL_ERR, "Duplicate parameter\n");
				cil_destroy_param(param);
				goto exit;
			}
		}

		cil_list_append(macro->params, CIL_PARAM, param);

		current_item = current_item->next;
	}

	/* we don't want the tree walker to walk the macro parameters (they were just handled above), so the subtree is deleted, and the next pointer of the
           node containing the macro name is updated to point to the start of the macro content */
	macro_content = parse_current->next->next->next;
	cil_tree_subtree_destroy(parse_current->next->next);
	parse_current->next->next = macro_content;
	if (macro_content == NULL) {
		/* No statements in macro and macro parameter list was last node */
		parse_current->parent->cl_tail = parse_current->next;
	}

	rc = cil_gen_node(db, ast_node, (struct cil_symtab_datum*)macro, (hashtab_key_t)key, CIL_SYM_BLOCKS, CIL_MACRO);
	if (rc != SEPOL_OK) {
		goto exit;
	}

	return SEPOL_OK;

exit:
	cil_tree_log(parse_current, CIL_ERR, "Bad macro declaration");
	cil_destroy_macro(macro);
	cil_clear_node(ast_node);
	return SEPOL_ERR;
}
int cil_gen_macro(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
{
	int rc = SEPOL_ERR;
	char *key = NULL;
	struct cil_macro *macro = NULL;
	struct cil_tree_node *macro_content = NULL;
	enum cil_syntax syntax[] = {
		CIL_SYN_STRING,
		CIL_SYN_STRING,
		CIL_SYN_LIST | CIL_SYN_EMPTY_LIST,
		CIL_SYN_N_LISTS | CIL_SYN_END,
		CIL_SYN_END
	};
	int syntax_len = sizeof(syntax)/ sizeof(*syntax);

	if (db == NULL || parse_current == NULL || ast_node == NULL) {
		goto exit;
	}

	rc =__cil_verify_syntax(parse_current, syntax, syntax_len);
	if (rc != SEPOL_OK) {
		goto exit;
	}

	cil_macro_init(&macro);

	key = parse_current->next->data;

	struct cil_tree_node *current_item = parse_current->next->next->cl_head;
	while (current_item != NULL) {
		enum cil_syntax param_syntax[] = {
			CIL_SYN_STRING,
			CIL_SYN_STRING,
			CIL_SYN_END
		};
		int param_syntax_len = sizeof(param_syntax)/sizeof(*param_syntax);
		char *kind = NULL;
		struct cil_param *param = NULL;

		rc =__cil_verify_syntax(current_item->cl_head, param_syntax, param_syntax_len);
		if (rc != SEPOL_OK) {
			goto exit;
		}

		if (macro->params == NULL) {
			cil_list_init(&macro->params, CIL_LIST_ITEM);
		}

		kind = current_item->cl_head->data;
		cil_param_init(&param);

		if (kind == CIL_KEY_TYPE) {
			param->flavor = CIL_TYPE;
		} else if (kind == CIL_KEY_ROLE) {
			param->flavor = CIL_ROLE;
		} else if (kind == CIL_KEY_USER) {
			param->flavor = CIL_USER;
		} else if (kind == CIL_KEY_SENSITIVITY) {
			param->flavor = CIL_SENS;
		} else if (kind == CIL_KEY_CATEGORY) {
			param->flavor = CIL_CAT;
		} else if (kind == CIL_KEY_CATSET) {
			param->flavor = CIL_CATSET;
		} else if (kind == CIL_KEY_LEVEL) {
			param->flavor = CIL_LEVEL;
		} else if (kind == CIL_KEY_LEVELRANGE) {
			param->flavor = CIL_LEVELRANGE;
		} else if (kind == CIL_KEY_CLASS) {
			param->flavor = CIL_CLASS;
		} else if (kind == CIL_KEY_IPADDR) {
			param->flavor = CIL_IPADDR;
		} else if (kind == CIL_KEY_MAP_CLASS) {
			param->flavor = CIL_MAP_CLASS;
		} else if (kind == CIL_KEY_CLASSPERMISSION) {
			param->flavor = CIL_CLASSPERMISSION;
		} else if (kind == CIL_KEY_BOOL) {
			param->flavor = CIL_BOOL;
		} else if (kind == CIL_KEY_STRING) {
			param->flavor = CIL_NAME;
		} else if (kind == CIL_KEY_NAME) {
			param->flavor = CIL_NAME;
		} else {
			cil_log(CIL_ERR, "The kind %s is not allowed as a parameter\n",kind);
			cil_destroy_param(param);
			goto exit;
		}

		param->str =  current_item->cl_head->next->data;

		rc = cil_verify_name(param->str, param->flavor);
		if (rc != SEPOL_OK) {
			cil_destroy_param(param);
			goto exit;
		}

		 
		struct cil_list_item *curr_param;
		cil_list_for_each(curr_param, macro->params) {
			if (param->str == ((struct cil_param*)curr_param->data)->str) {
				cil_log(CIL_ERR, "Duplicate parameter\n");
				cil_destroy_param(param);
				goto exit;
			}
		}

		cil_list_append(macro->params, CIL_PARAM, param);

		current_item = current_item->next;
	}

	 
	macro_content = parse_current->next->next->next;
	cil_tree_subtree_destroy(parse_current->next->next);
	parse_current->next->next = macro_content;
	if (macro_content == NULL) {
		 
		parse_current->parent->cl_tail = parse_current->next;
	}

	rc = cil_gen_node(db, ast_node, (struct cil_symtab_datum*)macro, (hashtab_key_t)key, CIL_SYM_BLOCKS, CIL_MACRO);
	if (rc != SEPOL_OK) {
		goto exit;
	}

	return SEPOL_OK;

exit:
	cil_tree_log(parse_current, CIL_ERR, "Bad macro declaration");
	cil_destroy_macro(macro);
	cil_clear_node(ast_node);
	return SEPOL_ERR;
}