int cil_resolve_call1(struct cil_tree_node *current, void *extra_args)
{
	struct cil_call *new_call = current->data;
	struct cil_args_resolve *args = extra_args;
	struct cil_db *db = NULL;
	struct cil_tree_node *macro_node = NULL;
	struct cil_symtab_datum *macro_datum = NULL;
	int rc = SEPOL_ERR;

	if (args != NULL) {
		db = args->db;
	}

	rc = cil_resolve_name(current, new_call->macro_str, CIL_SYM_BLOCKS, extra_args, &macro_datum);
	if (rc != SEPOL_OK) {
		goto exit;
	}

	macro_node = NODE(macro_datum);

	if (macro_node->flavor != CIL_MACRO) {
		cil_tree_log(current, CIL_ERR, "Failed to resolve %s to a macro", new_call->macro_str);
		rc = SEPOL_ERR;
		goto exit;
	}
	new_call->macro = (struct cil_macro*)macro_datum;

	if (new_call->macro->params != NULL ) {

		struct cil_list_item *item;
		struct cil_args *new_arg = NULL;
		struct cil_tree_node *pc = NULL;

		if (new_call->args_tree == NULL) {
			cil_tree_log(current, CIL_ERR, "Missing arguments");
			rc = SEPOL_ERR;
			goto exit;
		}

		pc = new_call->args_tree->root->cl_head;

		cil_list_init(&new_call->args, CIL_LIST_ITEM);

		cil_list_for_each(item, new_call->macro->params) {
			enum cil_flavor flavor = ((struct cil_param*)item->data)->flavor;

			if (pc == NULL) {
				cil_tree_log(current, CIL_ERR, "Missing arguments");
				rc = SEPOL_ERR;
				goto exit;
			}
			if (item->flavor != CIL_PARAM) {
				rc = SEPOL_ERR;
				goto exit;
			}

			cil_args_init(&new_arg);

			switch (flavor) {
			case CIL_NAME: {
				struct cil_name *name;
				if (pc->data == NULL) {
					cil_tree_log(current, CIL_ERR, "Invalid macro parameter");
					cil_destroy_args(new_arg);
					rc = SEPOL_ERR;
					goto exit;
				}
				name = __cil_insert_name(args->db, pc->data, current);
				if (name != NULL) {
					new_arg->arg = (struct cil_symtab_datum *)name;
				} else {
					new_arg->arg_str = pc->data;
				}
			}
				break;
			case CIL_TYPE:
				if (pc->data == NULL) {
					cil_tree_log(current, CIL_ERR, "Invalid macro parameter");
					cil_destroy_args(new_arg);
					rc = SEPOL_ERR;
					goto exit;
				}
				new_arg->arg_str = pc->data;
				break;
			case CIL_ROLE:
				if (pc->data == NULL) {
					cil_tree_log(current, CIL_ERR, "Invalid macro parameter");
					cil_destroy_args(new_arg);
					rc = SEPOL_ERR;
					goto exit;
				}
				new_arg->arg_str = pc->data;
				break;
			case CIL_USER:
				if (pc->data == NULL) {
					cil_tree_log(current, CIL_ERR, "Invalid macro parameter");
					cil_destroy_args(new_arg);
					rc = SEPOL_ERR;
					goto exit;
				}
				new_arg->arg_str = pc->data;
				break;
			case CIL_SENS:
				if (pc->data == NULL) {
					cil_tree_log(current, CIL_ERR, "Invalid macro parameter");
					cil_destroy_args(new_arg);
					rc = SEPOL_ERR;
					goto exit;
				}
				new_arg->arg_str = pc->data;
				break;
			case CIL_CAT:
				if (pc->data == NULL) {
					cil_tree_log(current, CIL_ERR, "Invalid macro parameter");
					cil_destroy_args(new_arg);
					rc = SEPOL_ERR;
					goto exit;
				}
				new_arg->arg_str = pc->data;
				break;
			case CIL_BOOL:
				if (pc->data == NULL) {
					cil_tree_log(current, CIL_ERR, "Invalid macro parameter");
					cil_destroy_args(new_arg);
					rc = SEPOL_ERR;
					goto exit;
				}
				new_arg->arg_str = pc->data;
				break;
			case CIL_CATSET: {
				if (pc->cl_head != NULL) {
					struct cil_catset *catset = NULL;
					struct cil_tree_node *cat_node = NULL;
					cil_catset_init(&catset);
					rc = cil_fill_cats(pc, &catset->cats);
					if (rc != SEPOL_OK) {
						cil_destroy_catset(catset);
						cil_destroy_args(new_arg);
						goto exit;
					}
					cil_tree_node_init(&cat_node);
					cat_node->flavor = CIL_CATSET;
					cat_node->data = catset;
					cil_list_append(((struct cil_symtab_datum*)catset)->nodes,
									CIL_LIST_ITEM, cat_node);
					new_arg->arg = (struct cil_symtab_datum*)catset;
				} else if (pc->data == NULL) {
					cil_tree_log(current, CIL_ERR, "Invalid macro parameter");
					cil_destroy_args(new_arg);
					rc = SEPOL_ERR;
					goto exit;
				} else {
					new_arg->arg_str = pc->data;
				}

				break;
			}
			case CIL_LEVEL: {
				if (pc->cl_head != NULL) {
					struct cil_level *level = NULL;
					struct cil_tree_node *lvl_node = NULL;
					cil_level_init(&level);

					rc = cil_fill_level(pc->cl_head, level);
					if (rc != SEPOL_OK) {
						cil_log(CIL_ERR, "Failed to create anonymous level, rc: %d\n", rc);
						cil_destroy_level(level);
						cil_destroy_args(new_arg);
						goto exit;
					}
					cil_tree_node_init(&lvl_node);
					lvl_node->flavor = CIL_LEVEL;
					lvl_node->data = level;
					cil_list_append(((struct cil_symtab_datum*)level)->nodes, 
									CIL_LIST_ITEM, lvl_node);
					new_arg->arg = (struct cil_symtab_datum*)level;
				} else if (pc->data == NULL) {
					cil_tree_log(current, CIL_ERR, "Invalid macro parameter");
					cil_destroy_args(new_arg);
					rc = SEPOL_ERR;
					goto exit;
				} else {
					new_arg->arg_str = pc->data;
				}

				break;
			}
			case CIL_LEVELRANGE: {
				if (pc->cl_head != NULL) {
					struct cil_levelrange *range = NULL;
					struct cil_tree_node *range_node = NULL;
					cil_levelrange_init(&range);

					rc = cil_fill_levelrange(pc->cl_head, range);
					if (rc != SEPOL_OK) {
						cil_log(CIL_ERR, "Failed to create anonymous levelrange, rc: %d\n", rc);
						cil_destroy_levelrange(range);
						cil_destroy_args(new_arg);
						goto exit;
					}
					cil_tree_node_init(&range_node);
					range_node->flavor = CIL_LEVELRANGE;
					range_node->data = range;
					cil_list_append(((struct cil_symtab_datum*)range)->nodes, 
									CIL_LIST_ITEM, range_node);
					new_arg->arg = (struct cil_symtab_datum*)range;
				} else if (pc->data == NULL) {
					cil_tree_log(current, CIL_ERR, "Invalid macro parameter");
					cil_destroy_args(new_arg);
					rc = SEPOL_ERR;
					goto exit;
				} else {
					new_arg->arg_str = pc->data;
				}

				break;
			}
			case CIL_IPADDR: {
				if (pc->cl_head != NULL) {
					struct cil_ipaddr *ipaddr = NULL;
					struct cil_tree_node *addr_node = NULL;
					cil_ipaddr_init(&ipaddr);

					rc = cil_fill_ipaddr(pc->cl_head, ipaddr);
					if (rc != SEPOL_OK) {
						cil_log(CIL_ERR, "Failed to create anonymous ip address, rc: %d\n", rc);
						cil_destroy_ipaddr(ipaddr);
						cil_destroy_args(new_arg);
						goto exit;
					}
					cil_tree_node_init(&addr_node);
					addr_node->flavor = CIL_IPADDR;
					addr_node->data = ipaddr;
					cil_list_append(((struct cil_symtab_datum*)ipaddr)->nodes,
									CIL_LIST_ITEM, addr_node);
					new_arg->arg = (struct cil_symtab_datum*)ipaddr;
				} else if (pc->data == NULL) {
					cil_tree_log(current, CIL_ERR, "Invalid macro parameter");
					cil_destroy_args(new_arg);
					rc = SEPOL_ERR;
					goto exit;
				} else {
					new_arg->arg_str = pc->data;
				}

				break;
			}
			case CIL_CLASS:
				if (pc->data == NULL) {
					cil_tree_log(current, CIL_ERR, "Invalid macro parameter");
					cil_destroy_args(new_arg);
					rc = SEPOL_ERR;
					goto exit;
				}
				new_arg->arg_str = pc->data;
				break;
			case CIL_MAP_CLASS:
				if (pc->data == NULL) {
					cil_tree_log(current, CIL_ERR, "Invalid macro parameter");
					cil_destroy_args(new_arg);
					rc = SEPOL_ERR;
					goto exit;
				}
				new_arg->arg_str = pc->data;
				break;
			case CIL_CLASSPERMISSION: {
				if (pc->cl_head != NULL) {
					struct cil_classpermission *cp = NULL;
					struct cil_tree_node *cp_node = NULL;

					cil_classpermission_init(&cp);
					rc = cil_fill_classperms_list(pc, &cp->classperms);
					if (rc != SEPOL_OK) {
						cil_log(CIL_ERR, "Failed to create anonymous classpermission\n");
						cil_destroy_classpermission(cp);
						cil_destroy_args(new_arg);
						goto exit;
					}
					cil_tree_node_init(&cp_node);
					cp_node->flavor = CIL_CLASSPERMISSION;
					cp_node->data = cp;
					cil_list_append(cp->datum.nodes, CIL_LIST_ITEM, cp_node);
					new_arg->arg = (struct cil_symtab_datum*)cp;
				} else if (pc->data == NULL) {
					cil_tree_log(current, CIL_ERR, "Invalid macro parameter");
					cil_destroy_args(new_arg);
					rc = SEPOL_ERR;
					goto exit;
				} else {
					new_arg->arg_str = pc->data;
				}
				break;
			}
			default:
				cil_log(CIL_ERR, "Unexpected flavor: %d\n", 
						(((struct cil_param*)item->data)->flavor));
				cil_destroy_args(new_arg);
				rc = SEPOL_ERR;
				goto exit;
			}
			new_arg->param_str = ((struct cil_param*)item->data)->str;
			new_arg->flavor = flavor;

			cil_list_append(new_call->args, CIL_ARGS, new_arg);

			pc = pc->next;
		}

		if (pc != NULL) {
			cil_tree_log(current, CIL_ERR, "Unexpected arguments");
			rc = SEPOL_ERR;
			goto exit;
		}
	} else if (new_call->args_tree != NULL) {
		cil_tree_log(current, CIL_ERR, "Unexpected arguments");
		rc = SEPOL_ERR;
		goto exit;
	}

	if (new_call->copied == 0) {
		new_call->copied = 1;

		rc = cil_check_recursive_call(current, macro_node);
		if (rc != SEPOL_OK) {
			goto exit;
		}

		rc = cil_copy_ast(db, macro_node, current);
		if (rc != SEPOL_OK) {
			cil_log(CIL_ERR, "Failed to copy macro, rc: %d\n", rc);
			goto exit;
		}
	}

	return SEPOL_OK;

exit:
	return rc;
}
int cil_resolve_call1(struct cil_tree_node *current, void *extra_args)
{
	struct cil_call *new_call = current->data;
	struct cil_args_resolve *args = extra_args;
	struct cil_db *db = NULL;
	struct cil_tree_node *macro_node = NULL;
	struct cil_symtab_datum *macro_datum = NULL;
	int rc = SEPOL_ERR;

	if (args != NULL) {
		db = args->db;
	}

	rc = cil_resolve_name(current, new_call->macro_str, CIL_SYM_BLOCKS, extra_args, &macro_datum);
	if (rc != SEPOL_OK) {
		goto exit;
	}

	macro_node = NODE(macro_datum);

	if (macro_node->flavor != CIL_MACRO) {
		cil_tree_log(current, CIL_ERR, "Failed to resolve %s to a macro", new_call->macro_str);
		rc = SEPOL_ERR;
		goto exit;
	}
	new_call->macro = (struct cil_macro*)macro_datum;

	if (new_call->macro->params != NULL ) {

		struct cil_list_item *item;
		struct cil_args *new_arg = NULL;
		struct cil_tree_node *pc = NULL;

		if (new_call->args_tree == NULL) {
			cil_tree_log(current, CIL_ERR, "Missing arguments");
			rc = SEPOL_ERR;
			goto exit;
		}

		pc = new_call->args_tree->root->cl_head;

		cil_list_init(&new_call->args, CIL_LIST_ITEM);

		cil_list_for_each(item, new_call->macro->params) {
			enum cil_flavor flavor = ((struct cil_param*)item->data)->flavor;

			if (pc == NULL) {
				cil_tree_log(current, CIL_ERR, "Missing arguments");
				rc = SEPOL_ERR;
				goto exit;
			}
			if (item->flavor != CIL_PARAM) {
				rc = SEPOL_ERR;
				goto exit;
			}

			cil_args_init(&new_arg);

			switch (flavor) {
			case CIL_NAME: {
				struct cil_name *name;
				if (pc->data == NULL) {
					cil_tree_log(current, CIL_ERR, "Invalid macro parameter");
					cil_destroy_args(new_arg);
					rc = SEPOL_ERR;
					goto exit;
				}
				name = __cil_insert_name(args->db, pc->data, current);
				if (name != NULL) {
					new_arg->arg = (struct cil_symtab_datum *)name;
				} else {
					new_arg->arg_str = pc->data;
				}
			}
				break;
			case CIL_TYPE:
				if (pc->data == NULL) {
					cil_tree_log(current, CIL_ERR, "Invalid macro parameter");
					cil_destroy_args(new_arg);
					rc = SEPOL_ERR;
					goto exit;
				}
				new_arg->arg_str = pc->data;
				break;
			case CIL_ROLE:
				if (pc->data == NULL) {
					cil_tree_log(current, CIL_ERR, "Invalid macro parameter");
					cil_destroy_args(new_arg);
					rc = SEPOL_ERR;
					goto exit;
				}
				new_arg->arg_str = pc->data;
				break;
			case CIL_USER:
				if (pc->data == NULL) {
					cil_tree_log(current, CIL_ERR, "Invalid macro parameter");
					cil_destroy_args(new_arg);
					rc = SEPOL_ERR;
					goto exit;
				}
				new_arg->arg_str = pc->data;
				break;
			case CIL_SENS:
				if (pc->data == NULL) {
					cil_tree_log(current, CIL_ERR, "Invalid macro parameter");
					cil_destroy_args(new_arg);
					rc = SEPOL_ERR;
					goto exit;
				}
				new_arg->arg_str = pc->data;
				break;
			case CIL_CAT:
				if (pc->data == NULL) {
					cil_tree_log(current, CIL_ERR, "Invalid macro parameter");
					cil_destroy_args(new_arg);
					rc = SEPOL_ERR;
					goto exit;
				}
				new_arg->arg_str = pc->data;
				break;
			case CIL_BOOL:
				if (pc->data == NULL) {
					cil_tree_log(current, CIL_ERR, "Invalid macro parameter");
					cil_destroy_args(new_arg);
					rc = SEPOL_ERR;
					goto exit;
				}
				new_arg->arg_str = pc->data;
				break;
			case CIL_CATSET: {
				if (pc->cl_head != NULL) {
					struct cil_catset *catset = NULL;
					struct cil_tree_node *cat_node = NULL;
					cil_catset_init(&catset);
					rc = cil_fill_cats(pc, &catset->cats);
					if (rc != SEPOL_OK) {
						cil_destroy_catset(catset);
						cil_destroy_args(new_arg);
						goto exit;
					}
					cil_tree_node_init(&cat_node);
					cat_node->flavor = CIL_CATSET;
					cat_node->data = catset;
					cil_list_append(((struct cil_symtab_datum*)catset)->nodes,
									CIL_LIST_ITEM, cat_node);
					new_arg->arg = (struct cil_symtab_datum*)catset;
				} else if (pc->data == NULL) {
					cil_tree_log(current, CIL_ERR, "Invalid macro parameter");
					cil_destroy_args(new_arg);
					rc = SEPOL_ERR;
					goto exit;
				} else {
					new_arg->arg_str = pc->data;
				}

				break;
			}
			case CIL_LEVEL: {
				if (pc->cl_head != NULL) {
					struct cil_level *level = NULL;
					struct cil_tree_node *lvl_node = NULL;
					cil_level_init(&level);

					rc = cil_fill_level(pc->cl_head, level);
					if (rc != SEPOL_OK) {
						cil_log(CIL_ERR, "Failed to create anonymous level, rc: %d\n", rc);
						cil_destroy_level(level);
						cil_destroy_args(new_arg);
						goto exit;
					}
					cil_tree_node_init(&lvl_node);
					lvl_node->flavor = CIL_LEVEL;
					lvl_node->data = level;
					cil_list_append(((struct cil_symtab_datum*)level)->nodes, 
									CIL_LIST_ITEM, lvl_node);
					new_arg->arg = (struct cil_symtab_datum*)level;
				} else if (pc->data == NULL) {
					cil_tree_log(current, CIL_ERR, "Invalid macro parameter");
					cil_destroy_args(new_arg);
					rc = SEPOL_ERR;
					goto exit;
				} else {
					new_arg->arg_str = pc->data;
				}

				break;
			}
			case CIL_LEVELRANGE: {
				if (pc->cl_head != NULL) {
					struct cil_levelrange *range = NULL;
					struct cil_tree_node *range_node = NULL;
					cil_levelrange_init(&range);

					rc = cil_fill_levelrange(pc->cl_head, range);
					if (rc != SEPOL_OK) {
						cil_log(CIL_ERR, "Failed to create anonymous levelrange, rc: %d\n", rc);
						cil_destroy_levelrange(range);
						cil_destroy_args(new_arg);
						goto exit;
					}
					cil_tree_node_init(&range_node);
					range_node->flavor = CIL_LEVELRANGE;
					range_node->data = range;
					cil_list_append(((struct cil_symtab_datum*)range)->nodes, 
									CIL_LIST_ITEM, range_node);
					new_arg->arg = (struct cil_symtab_datum*)range;
				} else if (pc->data == NULL) {
					cil_tree_log(current, CIL_ERR, "Invalid macro parameter");
					cil_destroy_args(new_arg);
					rc = SEPOL_ERR;
					goto exit;
				} else {
					new_arg->arg_str = pc->data;
				}

				break;
			}
			case CIL_IPADDR: {
				if (pc->cl_head != NULL) {
					struct cil_ipaddr *ipaddr = NULL;
					struct cil_tree_node *addr_node = NULL;
					cil_ipaddr_init(&ipaddr);

					rc = cil_fill_ipaddr(pc->cl_head, ipaddr);
					if (rc != SEPOL_OK) {
						cil_log(CIL_ERR, "Failed to create anonymous ip address, rc: %d\n", rc);
						cil_destroy_ipaddr(ipaddr);
						cil_destroy_args(new_arg);
						goto exit;
					}
					cil_tree_node_init(&addr_node);
					addr_node->flavor = CIL_IPADDR;
					addr_node->data = ipaddr;
					cil_list_append(((struct cil_symtab_datum*)ipaddr)->nodes,
									CIL_LIST_ITEM, addr_node);
					new_arg->arg = (struct cil_symtab_datum*)ipaddr;
				} else if (pc->data == NULL) {
					cil_tree_log(current, CIL_ERR, "Invalid macro parameter");
					cil_destroy_args(new_arg);
					rc = SEPOL_ERR;
					goto exit;
				} else {
					new_arg->arg_str = pc->data;
				}

				break;
			}
			case CIL_CLASS:
				if (pc->data == NULL) {
					cil_tree_log(current, CIL_ERR, "Invalid macro parameter");
					cil_destroy_args(new_arg);
					rc = SEPOL_ERR;
					goto exit;
				}
				new_arg->arg_str = pc->data;
				break;
			case CIL_MAP_CLASS:
				if (pc->data == NULL) {
					cil_tree_log(current, CIL_ERR, "Invalid macro parameter");
					cil_destroy_args(new_arg);
					rc = SEPOL_ERR;
					goto exit;
				}
				new_arg->arg_str = pc->data;
				break;
			case CIL_CLASSPERMISSION: {
				if (pc->cl_head != NULL) {
					struct cil_classpermission *cp = NULL;
					struct cil_tree_node *cp_node = NULL;

					cil_classpermission_init(&cp);
					rc = cil_fill_classperms_list(pc, &cp->classperms);
					if (rc != SEPOL_OK) {
						cil_log(CIL_ERR, "Failed to create anonymous classpermission\n");
						cil_destroy_classpermission(cp);
						cil_destroy_args(new_arg);
						goto exit;
					}
					cil_tree_node_init(&cp_node);
					cp_node->flavor = CIL_CLASSPERMISSION;
					cp_node->data = cp;
					cil_list_append(cp->datum.nodes, CIL_LIST_ITEM, cp_node);
					new_arg->arg = (struct cil_symtab_datum*)cp;
				} else if (pc->data == NULL) {
					cil_tree_log(current, CIL_ERR, "Invalid macro parameter");
					cil_destroy_args(new_arg);
					rc = SEPOL_ERR;
					goto exit;
				} else {
					new_arg->arg_str = pc->data;
				}
				break;
			}
			default:
				cil_log(CIL_ERR, "Unexpected flavor: %d\n", 
						(((struct cil_param*)item->data)->flavor));
				cil_destroy_args(new_arg);
				rc = SEPOL_ERR;
				goto exit;
			}
			new_arg->param_str = ((struct cil_param*)item->data)->str;
			new_arg->flavor = flavor;

			cil_list_append(new_call->args, CIL_ARGS, new_arg);

			pc = pc->next;
		}

		if (pc != NULL) {
			cil_tree_log(current, CIL_ERR, "Unexpected arguments");
			rc = SEPOL_ERR;
			goto exit;
		}
	} else if (new_call->args_tree != NULL) {
		cil_tree_log(current, CIL_ERR, "Unexpected arguments");
		rc = SEPOL_ERR;
		goto exit;
	}

	if (new_call->copied == 0) {
		new_call->copied = 1;

		rc = cil_check_recursive_call(current, macro_node);
		if (rc != SEPOL_OK) {
			goto exit;
		}

		rc = cil_copy_ast(db, macro_node, current);
		if (rc != SEPOL_OK) {
			cil_log(CIL_ERR, "Failed to copy macro, rc: %d\n", rc);
			goto exit;
		}
	}

	return SEPOL_OK;

exit:
	return rc;
}