Changeset - r27212:5b91b1753581
[Not reviewed]
master
0 4 0
Rubidium - 14 months ago 2023-04-27 17:21:06
rubidium@openttd.org
Codechange: use std::string instead of stredup/free for stories
4 files changed with 30 insertions and 40 deletions:
0 comments (0 inline, 0 general)
src/saveload/story_sl.cpp
Show inline comments
 
@@ -32,13 +32,13 @@ static const SaveLoad _story_page_elemen
 
	SLE_CONDVAR(StoryPageElement, sort_value,    SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION,   SLV_185),
 
	SLE_CONDVAR(StoryPageElement, sort_value,    SLE_UINT32,                 SLV_185, SL_MAX_VERSION),
 
	    SLE_VAR(StoryPageElement, page,          SLE_UINT16),
 
	SLE_CONDVAR(StoryPageElement, type,          SLE_FILE_U16 | SLE_VAR_U8,  SL_MIN_VERSION,   SLV_185),
 
	SLE_CONDVAR(StoryPageElement, type,          SLE_UINT8,                  SLV_185, SL_MAX_VERSION),
 
	    SLE_VAR(StoryPageElement, referenced_id, SLE_UINT32),
 
	    SLE_STR(StoryPageElement, text,          SLE_STR | SLF_ALLOW_CONTROL, 0),
 
	   SLE_SSTR(StoryPageElement, text,          SLE_STR | SLF_ALLOW_CONTROL),
 
};
 

	
 
struct STPEChunkHandler : ChunkHandler {
 
	STPEChunkHandler() : ChunkHandler('STPE', CH_TABLE) {}
 

	
 
	void Save() const override
 
@@ -74,13 +74,13 @@ struct STPEChunkHandler : ChunkHandler {
 
static const SaveLoad _story_pages_desc[] = {
 
	SLE_CONDVAR(StoryPage, sort_value, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION,   SLV_185),
 
	SLE_CONDVAR(StoryPage, sort_value, SLE_UINT32,                 SLV_185, SL_MAX_VERSION),
 
	    SLE_VAR(StoryPage, date,       SLE_UINT32),
 
	SLE_CONDVAR(StoryPage, company,    SLE_FILE_U16 | SLE_VAR_U8,  SL_MIN_VERSION,   SLV_185),
 
	SLE_CONDVAR(StoryPage, company,    SLE_UINT8,                  SLV_185, SL_MAX_VERSION),
 
	    SLE_STR(StoryPage, title,      SLE_STR | SLF_ALLOW_CONTROL, 0),
 
	   SLE_SSTR(StoryPage, title,      SLE_STR | SLF_ALLOW_CONTROL),
 
};
 

	
 
struct STPAChunkHandler : ChunkHandler {
 
	STPAChunkHandler() : ChunkHandler('STPA', CH_TABLE) {}
 

	
 
	void Save() const override
src/story.cpp
Show inline comments
 
@@ -44,22 +44,22 @@ INSTANTIATE_POOL_METHODS(StoryPage)
 
 * @param type The type of the page element to create/update
 
 * @param tile The tile parameter of the DoCommand proc
 
 * @param reference The reference parameter of the DoCommand proc (p2)
 
 * @param text The text parameter of the DoCommand proc
 
 * @return true, if and only if the given parameters are valid for the given page element type and page id.
 
 */
 
static bool VerifyElementContentParameters(StoryPageID page_id, StoryPageElementType type, TileIndex tile, uint32 reference, const char *text)
 
static bool VerifyElementContentParameters(StoryPageID page_id, StoryPageElementType type, TileIndex tile, uint32 reference, const std::string &text)
 
{
 
	StoryPageButtonData button_data{ reference };
 

	
 
	switch (type) {
 
		case SPET_TEXT:
 
			if (StrEmpty(text)) return false;
 
			if (text.empty()) return false;
 
			break;
 
		case SPET_LOCATION:
 
			if (StrEmpty(text)) return false;
 
			if (text.empty()) return false;
 
			if (!IsValidTile(tile)) return false;
 
			break;
 
		case SPET_GOAL:
 
			if (!Goal::IsValidID((GoalID)reference)) return false;
 
			/* Reject company specific goals on global pages */
 
			if (StoryPage::Get(page_id)->company == INVALID_COMPANY && Goal::Get((GoalID)reference)->company != INVALID_COMPANY) return false;
 
@@ -88,29 +88,29 @@ static bool VerifyElementContentParamete
 
 * element with new content data.
 
 * @param pe The page element to update
 
 * @param tile The tile parameter of the DoCommand proc
 
 * @param reference The reference parameter of the DoCommand proc (p2)
 
 * @param text The text parameter of the DoCommand proc
 
 */
 
static void UpdateElement(StoryPageElement &pe, TileIndex tile, uint32 reference, const char *text)
 
static void UpdateElement(StoryPageElement &pe, TileIndex tile, uint32 reference, const std::string &text)
 
{
 
	switch (pe.type) {
 
		case SPET_TEXT:
 
			pe.text = stredup(text);
 
			pe.text = text;
 
			break;
 
		case SPET_LOCATION:
 
			pe.text = stredup(text);
 
			pe.text = text;
 
			pe.referenced_id = tile;
 
			break;
 
		case SPET_GOAL:
 
			pe.referenced_id = (GoalID)reference;
 
			break;
 
		case SPET_BUTTON_PUSH:
 
		case SPET_BUTTON_TILE:
 
		case SPET_BUTTON_VEHICLE:
 
			pe.text = stredup(text);
 
			pe.text = text;
 
			pe.referenced_id = reference;
 
			break;
 
		default: NOT_REACHED();
 
	}
 
}
 

	
 
@@ -217,17 +217,13 @@ std::tuple<CommandCost, StoryPageID> Cmd
 
		}
 

	
 
		StoryPage *s = new StoryPage();
 
		s->sort_value = _story_page_next_sort_value;
 
		s->date = TimerGameCalendar::date;
 
		s->company = company;
 
		if (text.empty()) {
 
			s->title = nullptr;
 
		} else {
 
			s->title = stredup(text.c_str());
 
		}
 
		s->title = text;
 

	
 
		InvalidateWindowClassesData(WC_STORY_BOOK, -1);
 
		if (StoryPage::GetNumItems() == 1) InvalidateWindowData(WC_MAIN_TOOLBAR, 0);
 

	
 
		_story_page_next_sort_value++;
 
		return { CommandCost(), s->index };
 
@@ -256,26 +252,26 @@ std::tuple<CommandCost, StoryPageElement
 
		if (iter->page == page_id) element_count++;
 
	}
 
	if (element_count >= 128) return { CMD_ERROR, INVALID_STORY_PAGE_ELEMENT };
 

	
 
	if (_current_company != OWNER_DEITY) return { CMD_ERROR, INVALID_STORY_PAGE_ELEMENT };
 
	if (!StoryPage::IsValidID(page_id)) return { CMD_ERROR, INVALID_STORY_PAGE_ELEMENT };
 
	if (!VerifyElementContentParameters(page_id, type, tile, reference, text.c_str())) return { CMD_ERROR, INVALID_STORY_PAGE_ELEMENT };
 
	if (!VerifyElementContentParameters(page_id, type, tile, reference, text)) return { CMD_ERROR, INVALID_STORY_PAGE_ELEMENT };
 

	
 

	
 
	if (flags & DC_EXEC) {
 
		if (_story_page_element_pool.items == 0) {
 
			/* Initialize the next sort value variable. */
 
			_story_page_element_next_sort_value = 0;
 
		}
 

	
 
		StoryPageElement *pe = new StoryPageElement();
 
		pe->sort_value = _story_page_element_next_sort_value;
 
		pe->type = type;
 
		pe->page = page_id;
 
		UpdateElement(*pe, tile, reference, text.c_str());
 
		UpdateElement(*pe, tile, reference, text);
 

	
 
		InvalidateWindowClassesData(WC_STORY_BOOK, page_id);
 

	
 
		_story_page_element_next_sort_value++;
 
		return { CommandCost(), pe->index };
 
	}
 
@@ -298,16 +294,16 @@ CommandCost CmdUpdateStoryPageElement(Do
 
	if (!StoryPageElement::IsValidID(page_element_id)) return CMD_ERROR;
 

	
 
	StoryPageElement *pe = StoryPageElement::Get(page_element_id);
 
	StoryPageID page_id = pe->page;
 
	StoryPageElementType type = pe->type;
 

	
 
	if (!VerifyElementContentParameters(page_id, type, tile, reference, text.c_str())) return CMD_ERROR;
 
	if (!VerifyElementContentParameters(page_id, type, tile, reference, text)) return CMD_ERROR;
 

	
 
	if (flags & DC_EXEC) {
 
		UpdateElement(*pe, tile, reference, text.c_str());
 
		UpdateElement(*pe, tile, reference, text);
 
		InvalidateWindowClassesData(WC_STORY_BOOK, pe->page);
 
	}
 

	
 
	return CommandCost();
 
}
 

	
 
@@ -322,18 +318,13 @@ CommandCost CmdSetStoryPageTitle(DoComma
 
{
 
	if (_current_company != OWNER_DEITY) return CMD_ERROR;
 
	if (!StoryPage::IsValidID(page_id)) return CMD_ERROR;
 

	
 
	if (flags & DC_EXEC) {
 
		StoryPage *p = StoryPage::Get(page_id);
 
		free(p->title);
 
		if (text.empty()) {
 
			p->title = nullptr;
 
		} else {
 
			p->title = stredup(text.c_str());
 
		}
 
		p->title = text;
 

	
 
		InvalidateWindowClassesData(WC_STORY_BOOK, page_id);
 
	}
 

	
 
	return CommandCost();
 
}
src/story_base.h
Show inline comments
 
@@ -144,32 +144,32 @@ struct StoryPageButtonData {
 
struct StoryPageElement : StoryPageElementPool::PoolItem<&_story_page_element_pool> {
 
	uint32 sort_value;         ///< A number that increases for every created story page element. Used for sorting. The id of a story page element is the pool index.
 
	StoryPageID page;          ///< Id of the page which the page element belongs to
 
	StoryPageElementType type; ///< Type of page element
 

	
 
	uint32 referenced_id;      ///< Id of referenced object (location, goal etc.)
 
	char *text;                ///< Static content text of page element
 
	std::string text;          ///< Static content text of page element
 

	
 
	/**
 
	 * We need an (empty) constructor so struct isn't zeroed (as C++ standard states)
 
	 */
 
	inline StoryPageElement() { }
 

	
 
	/**
 
	 * (Empty) destructor has to be defined else operator delete might be called with nullptr parameter
 
	 */
 
	inline ~StoryPageElement() { free(this->text); }
 
	inline ~StoryPageElement() { }
 
};
 

	
 
/** Struct about stories, current and completed */
 
struct StoryPage : StoryPagePool::PoolItem<&_story_page_pool> {
 
	uint32 sort_value;   ///< A number that increases for every created story page. Used for sorting. The id of a story page is the pool index.
 
	uint32 sort_value;            ///< A number that increases for every created story page. Used for sorting. The id of a story page is the pool index.
 
	TimerGameCalendar::Date date; ///< Date when the page was created.
 
	CompanyID company;   ///< StoryPage is for a specific company; INVALID_COMPANY if it is global
 
	CompanyID company;            ///< StoryPage is for a specific company; INVALID_COMPANY if it is global
 

	
 
	char *title;         ///< Title of story page
 
	std::string title;            ///< Title of story page
 

	
 
	/**
 
	 * We need an (empty) constructor so struct isn't zeroed (as C++ standard states)
 
	 */
 
	inline StoryPage() { }
 

	
 
@@ -180,12 +180,11 @@ struct StoryPage : StoryPagePool::PoolIt
 
	{
 
		if (!this->CleaningPool()) {
 
			for (StoryPageElement *spe : StoryPageElement::Iterate()) {
 
				if (spe->page == this->index) delete spe;
 
			}
 
		}
 
		free(this->title);
 
	}
 
};
 

	
 
#endif /* STORY_BASE_H */
 

	
src/story_gui.cpp
Show inline comments
 
@@ -57,13 +57,13 @@ protected:
 
	Scrollbar *vscroll;                ///< Scrollbar of the page text.
 
	mutable LayoutCache layout_cache;  ///< Cached element layout.
 

	
 
	GUIStoryPageList story_pages;      ///< Sorted list of pages.
 
	GUIStoryPageElementList story_page_elements; ///< Sorted list of page elements that belong to the current page.
 
	StoryPageID selected_page_id;      ///< Pool index of selected page.
 
	char selected_generic_title[255];  ///< If the selected page doesn't have a custom title, this buffer is used to store a generic page title.
 
	std::string selected_generic_title;  ///< If the selected page doesn't have a custom title, this buffer is used to store a generic page title.
 

	
 
	StoryPageElementID active_button_id; ///< Which button element the player is currently using
 

	
 
	static GUIStoryPageList::SortFunction * const page_sorter_funcs[];
 
	static GUIStoryPageElementList::SortFunction * const page_element_sorter_funcs[];
 

	
 
@@ -185,15 +185,15 @@ protected:
 
	 * Updates the content of selected page.
 
	 */
 
	void RefreshSelectedPage()
 
	{
 
		/* Generate generic title if selected page have no custom title. */
 
		StoryPage *page = this->GetSelPage();
 
		if (page != nullptr && page->title == nullptr) {
 
		if (page != nullptr && page->title.empty()) {
 
			SetDParam(0, GetSelPageNum() + 1);
 
			GetString(selected_generic_title, STR_STORY_BOOK_GENERIC_PAGE_ITEM, lastof(selected_generic_title));
 
			selected_generic_title = GetString(STR_STORY_BOOK_GENERIC_PAGE_ITEM);
 
		}
 

	
 
		this->story_page_elements.ForceRebuild();
 
		this->BuildStoryPageElementList();
 

	
 
		if (this->active_button_id != INVALID_STORY_PAGE_ELEMENT) ResetObjectToPlace();
 
@@ -252,13 +252,13 @@ protected:
 
	{
 
		DropDownList list;
 
		uint16 page_num = 1;
 
		for (const StoryPage *p : this->story_pages) {
 
			bool current_page = p->index == this->selected_page_id;
 
			DropDownListStringItem *item = nullptr;
 
			if (p->title != nullptr) {
 
			if (!p->title.empty()) {
 
				item = new DropDownListCharStringItem(p->title, p->index, current_page);
 
			} else {
 
				/* No custom title => use a generic page title with page number. */
 
				DropDownListParamStringItem *str_item =
 
						new DropDownListParamStringItem(STR_STORY_BOOK_GENERIC_PAGE_ITEM, p->index, current_page);
 
				str_item->SetParam(0, page_num);
 
@@ -292,13 +292,13 @@ protected:
 
		StoryPage *page = this->GetSelPage();
 
		if (page == nullptr) return 0;
 
		int height = 0;
 

	
 
		/* Title lines */
 
		height += FONT_HEIGHT_NORMAL; // Date always use exactly one line.
 
		SetDParamStr(0, page->title != nullptr ? page->title : this->selected_generic_title);
 
		SetDParamStr(0, !page->title.empty() ? page->title : this->selected_generic_title);
 
		height += GetStringHeight(STR_STORY_BOOK_TITLE, max_width);
 

	
 
		return height;
 
	}
 

	
 
	/**
 
@@ -613,13 +613,13 @@ public:
 
		/* story_page_elements will get built by SetSelectedPage */
 

	
 
		this->FinishInitNested(window_number);
 
		this->owner = (Owner)this->window_number;
 

	
 
		/* Initialize selected vars. */
 
		this->selected_generic_title[0] = '\0';
 
		this->selected_generic_title.clear();
 
		this->selected_page_id = INVALID_STORY_PAGE;
 

	
 
		this->active_button_id = INVALID_STORY_PAGE_ELEMENT;
 

	
 
		this->OnInvalidateData(-1);
 
	}
 
@@ -652,13 +652,13 @@ public:
 

	
 
	void SetStringParameters(int widget) const override
 
	{
 
		switch (widget) {
 
			case WID_SB_SEL_PAGE: {
 
				StoryPage *page = this->GetSelPage();
 
				SetDParamStr(0, page != nullptr && page->title != nullptr ? page->title : this->selected_generic_title);
 
				SetDParamStr(0, page != nullptr && !page->title.empty() ? page->title : this->selected_generic_title);
 
				break;
 
			}
 
			case WID_SB_CAPTION:
 
				if (this->window_number == INVALID_COMPANY) {
 
					SetDParam(0, STR_STORY_BOOK_SPECTATOR_CAPTION);
 
				} else {
 
@@ -710,13 +710,13 @@ public:
 
			SetDParam(0, page->date);
 
			DrawString(0, fr.right, y_offset, STR_JUST_DATE_LONG, TC_BLACK);
 
		}
 
		y_offset += line_height;
 

	
 
		/* Title */
 
		SetDParamStr(0, page->title != nullptr ? page->title : this->selected_generic_title);
 
		SetDParamStr(0, !page->title.empty() ? page->title : this->selected_generic_title);
 
		y_offset = DrawStringMultiLine(0, fr.right, y_offset, fr.bottom, STR_STORY_BOOK_TITLE, TC_BLACK, SA_TOP | SA_HOR_CENTER);
 

	
 
		/* Page elements */
 
		this->EnsureStoryPageElementLayout();
 
		for (const LayoutCacheElement &ce : this->layout_cache) {
 
			y_offset = ce.bounds.top - scrollpos;
 
@@ -770,13 +770,13 @@ public:
 
			case WID_SB_SEL_PAGE: {
 

	
 
				/* Get max title width. */
 
				for (size_t i = 0; i < this->story_pages.size(); i++) {
 
					const StoryPage *s = this->story_pages[i];
 

	
 
					if (s->title != nullptr) {
 
					if (!s->title.empty()) {
 
						SetDParamStr(0, s->title);
 
					} else {
 
						SetDParamStr(0, this->selected_generic_title);
 
					}
 
					Dimension title_d = GetStringBoundingBox(STR_BLACK_RAW_STRING);
 

	
 
@@ -874,13 +874,13 @@ public:
 
		if (data == -1) {
 
			this->story_pages.ForceRebuild();
 
			this->BuildStoryPageList();
 

	
 
			/* Was the last page removed? */
 
			if (this->story_pages.size() == 0) {
 
				this->selected_generic_title[0] = '\0';
 
				this->selected_generic_title.clear();
 
			}
 

	
 
			/* Verify page selection. */
 
			if (!_story_page_pool.IsValidID(this->selected_page_id)) {
 
				this->selected_page_id = INVALID_STORY_PAGE;
 
			}
0 comments (0 inline, 0 general)