void sub_write(char *arg, char_data *ch, byte find_invis, int targets) {
	char str[MAX_INPUT_LENGTH * 2];
	char type[MAX_INPUT_LENGTH], name[MAX_INPUT_LENGTH];
	char *tokens[MAX_INPUT_LENGTH], *s, *p;
	void *otokens[MAX_INPUT_LENGTH];
	char_data *to;
	obj_data *obj;
	int i;
	int to_sleeping = 1, is_spammy = 0; /* mainly for windows compiles */

	if (!arg)
		return;

	tokens[0] = str;

	for (i = 0, p = arg, s = str; *p;) {
		switch (*p) {
			case '~':
			case '|':
			case '^':
			// case '&':	// removed this because it conflicts with color codes
			case '*': {
				/* get char_data, move to next token */
				type[i] = *p;
				*s = '\0';
				p = any_one_name(++p, name);
				otokens[i] = find_invis ? get_char_in_room(IN_ROOM(ch), name) : get_char_room_vis(ch, name);
				tokens[++i] = ++s;
				break;
			}

			case '@': {
				/* get obj_data, move to next token */
				type[i] = *p;
				*s = '\0';
				p = any_one_name(++p, name);

				if (find_invis)
					obj = get_obj_in_room(IN_ROOM(ch), name);
				else if (!(obj = get_obj_in_list_vis(ch, name, ROOM_CONTENTS(IN_ROOM(ch))))) {
					// nothing
				}
				else if (!(obj = get_obj_in_equip_vis(ch, name, ch->equipment))) {
					// nothing
				}
				else {
					obj = get_obj_in_list_vis(ch, name, ch->carrying);
				}

				otokens[i] = obj;
				tokens[++i] = ++s;
				break;
			}

			case '\\': {
				p++;
				*s++ = *p++;
				break;
			}

			default: {
				*s++ = *p++;
			}
		}
	}

	*s = '\0';
	tokens[++i] = NULL;

	if (IS_SET(targets, TO_CHAR) && SENDOK(ch) && (AWAKE(ch) || IS_SET(targets, TO_SLEEP)))
		sub_write_to_char(ch, tokens, otokens, type);

	if (IS_SET(targets, TO_ROOM)) {
		for (to = ROOM_PEOPLE(IN_ROOM(ch)); to; to = to->next_in_room) {
			if (to != ch && SENDOK(to) && (AWAKE(to) || IS_SET(targets, TO_SLEEP))) {
				sub_write_to_char(to, tokens, otokens, type);
			}
		}
	}
}
/**
* WARNING: This function actually deletes a building.
*
* @param char_data *ch The person doing the deleting.
* @param bld_vnum vnum The vnum to delete.
*/
void olc_delete_building(char_data *ch, bld_vnum vnum) {
	void check_for_bad_buildings();
	extern bool delete_link_rule_by_type_value(struct adventure_link_rule **list, int type, any_vnum value);
	void remove_building_from_table(bld_data *bld);
	
	descriptor_data *desc;
	room_data *room, *next_room;
	craft_data *craft, *next_craft;
	adv_data *adv, *next_adv;
	bld_data *bld;
	int count;
	bool found, deleted = FALSE;
	
	if (!(bld = building_proto(vnum))) {
		msg_to_char(ch, "There is no such building %d.\r\n", vnum);
		return;
	}
	
	if (HASH_COUNT(building_table) <= 1) {
		msg_to_char(ch, "You can't delete the last building.\r\n");
		return;
	}
	
	// pull from hash
	remove_building_from_table(bld);

	// save index and building file now
	save_index(DB_BOOT_BLD);
	save_library_file_for_vnum(DB_BOOT_BLD, vnum);
	
	// update world
	count = 0;
	HASH_ITER(world_hh, world_table, room, next_room) {
		if (IS_ANY_BUILDING(room) && BUILDING_VNUM(room) == vnum) {
			if (GET_ROOM_VNUM(room) >= MAP_SIZE) {
				delete_room(room, FALSE);	// must call check_all_exits
				deleted = TRUE;
			}
			else {
				// map room
				if (ROOM_PEOPLE(room)) {
					act("The building has been deleted.", FALSE, ROOM_PEOPLE(room), NULL, NULL, TO_CHAR | TO_ROOM);
				}
				disassociate_building(room);
			}
		}
	}
	if (deleted) {
		check_all_exits();
	}
	
	// adventure zones
	HASH_ITER(hh, adventure_table, adv, next_adv) {
		found = delete_link_rule_by_type_value(&GET_ADV_LINKING(adv), ADV_LINK_BUILDING_EXISTING, vnum);
		found |= delete_link_rule_by_type_value(&GET_ADV_LINKING(adv), ADV_LINK_BUILDING_NEW, vnum);
		found |= delete_link_rule_by_type_value(&GET_ADV_LINKING(adv), ADV_LINK_PORTAL_BUILDING_EXISTING, vnum);
		found |= delete_link_rule_by_type_value(&GET_ADV_LINKING(adv), ADV_LINK_PORTAL_BUILDING_NEW, vnum);
		
		if (found) {
			save_library_file_for_vnum(DB_BOOT_ADV, GET_ADV_VNUM(adv));
		}
	}