winix/templates/miscspace.cpp

406 lines
8.9 KiB
C++

/*
* This file is a part of Winix
* and is distributed under the 2-Clause BSD licence.
* Author: Tomasz Sowa <t.sowa@ttmath.org>
*/
/*
* Copyright (c) 2012-2014, Tomasz Sowa
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "templates.h"
namespace Winix
{
namespace TemplatesFunctions
{
bool are_spaces_the_same(const std::vector<Ezc::Var> & params, const std::vector<std::wstring> & spaces)
{
// last value from params is the parameter name (not a space)
if( spaces.size() + 1 != params.size() )
return false;
for(size_t i=0 ; i<spaces.size() ; ++i)
if( spaces[i] != params[i].str )
return false;
return true;
}
void copy_space(const std::vector<Ezc::Var> & params, std::vector<std::wstring> & spaces)
{
if( !params.empty() )
{
spaces.resize(params.size() - 1);
for(size_t i=0 ; i<params.size() - 1 ; ++i)
spaces[i] = params[i].str;
}
else
{
spaces.clear();
}
}
PT::Space * find_space(const std::vector<Ezc::Var> & params, PT::Space & space, size_t level = 0)
{
if( level + 1 < params.size() )
{
for(size_t i=0 ; i<space.spaces.size() ; ++i)
{
if( space.spaces[i]->name == params[level].str )
return find_space(params, *space.spaces[i], level+1);
}
// there is no such a space
return 0;
}
else
{
return &space;
}
}
struct SpaceInfo
{
bool inited;
PT::Space * last_space;
std::vector<std::wstring> spaces;
SpaceInfo()
{
inited = false;
last_space = 0;
}
};
static std::map<PT::Space*, SpaceInfo> spaces_map;
static size_t space_reqid = 0;
void space_init(const std::vector<Ezc::Var> & params, PT::Space & space, SpaceInfo & space_info)
{
if( !space_info.inited || !are_spaces_the_same(params, space_info.spaces) )
{
space_info.inited = true;
copy_space(params, space_info.spaces);
space_info.last_space = find_space(params, space);
}
else
{
// !! temp
//log << log1 << "taking space from the cache" << logend;
}
}
void space_check_reqid()
{
if( space_reqid != cur->request->id )
{
space_reqid = cur->request->id;
spaces_map.clear();
}
}
void space(Info & i, PT::Space & space)
{
space_check_reqid();
if( !i.params.empty() )
{
SpaceInfo & space_info = spaces_map[&space];
space_init(i.params, space, space_info);
if( space_info.last_space )
{
const std::wstring & param = i.params.back().str;
const std::wstring * value = space_info.last_space->GetValue(param);
if( value )
i.out << *value;
// else
// log << log1 << "nie ma takiej wartosci" << logend; // only for testing
// !! IMPROVE ME
}
}
}
void space_value_noescape(Info & i, PT::Space & space)
{
space_check_reqid();
if( !i.params.empty() )
{
SpaceInfo & space_info = spaces_map[&space];
space_init(i.params, space, space_info);
if( space_info.last_space )
{
const std::wstring & param = i.params.back().str;
const std::wstring * value = space_info.last_space->GetValue(param);
if( value )
i.out << R(*value);
}
}
}
/*
stack item for [for] statement
*/
struct SpaceStackItem
{
// names of the spaces
std::vector<std::wstring> spaces;
// table of values
std::vector<std::wstring> values;
// an index to 'values' which is incremented every each [for]
size_t value_index;
SpaceStackItem()
{
value_index = 0;
}
};
/*
each Space has its own SpacesTabInfo struct
*/
struct SpacesTabInfo
{
// a stack for [for] statements
std::vector<SpaceStackItem> stack_tab;
// current item from 'stack_tab'
size_t cur_stack;
SpacesTabInfo()
{
cur_stack = 0;
}
};
static std::map<PT::Space*, SpacesTabInfo> spaces_tab_info_map;
static size_t spaces_tab_reqid = 0;
bool spaces_tab_find_stack_item(std::vector<Ezc::Var> & params, SpacesTabInfo & spaces_tab_info)
{
bool found = false;
spaces_tab_info.cur_stack = spaces_tab_info.stack_tab.size();
for(size_t i=0 ; i<spaces_tab_info.stack_tab.size() ; ++i)
{
if( are_spaces_the_same(params, spaces_tab_info.stack_tab[i].spaces) )
{
spaces_tab_info.cur_stack = i;
found = true;
break;
}
}
return found;
}
void spaces_tab_add_to_stack(std::vector<Ezc::Var> & params, PT::Space & space, SpacesTabInfo & spaces_tab_info)
{
if( !params.empty() )
{
// adding a new item at the end (with the default constructor)
spaces_tab_info.stack_tab.resize(spaces_tab_info.stack_tab.size() + 1);
spaces_tab_info.cur_stack = spaces_tab_info.stack_tab.size() - 1;
SpaceStackItem & stack_item = spaces_tab_info.stack_tab.back();
copy_space(params, stack_item.spaces);
space.ListText(params.back().str, stack_item.values);
stack_item.value_index = 0;
}
}
void spaces_tab_check_reqid()
{
if( spaces_tab_reqid != cur->request->id )
{
spaces_tab_reqid = cur->request->id;
spaces_tab_info_map.clear();
}
}
void spaces_tab_init(std::vector<Ezc::Var> & params, PT::Space & space, SpacesTabInfo & spaces_tab_info)
{
PT::Space * child_space = find_space(params, space);
if( child_space )
{
if( !spaces_tab_find_stack_item(params, spaces_tab_info) )
{
// add a new value to the stack
spaces_tab_add_to_stack(params, *child_space, spaces_tab_info);
}
}
else
{
// there is not such a space
spaces_tab_info.cur_stack = spaces_tab_info.stack_tab.size();
}
}
void spaces_tab(Info & i, PT::Space & space)
{
spaces_tab_check_reqid();
if( !i.params.empty() )
{
SpacesTabInfo & spaces_tab_info = spaces_tab_info_map[&space];
spaces_tab_init(i.params, space, spaces_tab_info);
if( spaces_tab_info.cur_stack < spaces_tab_info.stack_tab.size() )
{
SpaceStackItem & stack_item = spaces_tab_info.stack_tab[spaces_tab_info.cur_stack];
// !! CHECK ME there was a change in EZC lately
// make sure this still is ok
// i.iter is different for each [for] statement (implemented in EZC)
// so we don't have to remember it in our stack
// for each the same space we have only one item in the stack, e.g.
// [for item_meta "space1" "space2" "value"]
// [for item_meta "space1" "space2" "value"]
// [end]
// [end]
// above two [for]s use the same item on our stack
stack_item.value_index = i.iter;
i.res = stack_item.value_index < stack_item.values.size();
}
}
}
void spaces_tab_value_print(HtmlTextStream & out, SpacesTabInfo & spaces_tab_info)
{
if( spaces_tab_info.cur_stack < spaces_tab_info.stack_tab.size() )
{
SpaceStackItem & stack_item = spaces_tab_info.stack_tab[spaces_tab_info.cur_stack];
out << stack_item.values[stack_item.value_index];
}
}
void spaces_tab_value(Info & i, PT::Space & space)
{
spaces_tab_check_reqid();
SpacesTabInfo & spaces_tab_info = spaces_tab_info_map[&space];
if( i.params.empty() )
{
// value from last [for ...] statement
spaces_tab_value_print(i.out, spaces_tab_info);
}
else
{
size_t cur_stack_old = spaces_tab_info.cur_stack;
if( spaces_tab_find_stack_item(i.params, spaces_tab_info) )
spaces_tab_value_print(i.out, spaces_tab_info);
spaces_tab_info.cur_stack = cur_stack_old;
}
}
bool spaces_tab_has_next(SpacesTabInfo & spaces_tab_info)
{
if( spaces_tab_info.cur_stack < spaces_tab_info.stack_tab.size() )
{
SpaceStackItem & val = spaces_tab_info.stack_tab[spaces_tab_info.cur_stack];
return val.value_index + 1 < val.values.size();
}
return false;
}
void spaces_tab_has_next(Info & i, PT::Space & space)
{
spaces_tab_check_reqid();
SpacesTabInfo & spaces_tab_info = spaces_tab_info_map[&space];
if( i.params.empty() )
{
// value from last [for ...] statement
i.res = spaces_tab_has_next(spaces_tab_info);
}
else
{
size_t cur_stack_old = spaces_tab_info.cur_stack;
if( spaces_tab_find_stack_item(i.params, spaces_tab_info) )
i.res = spaces_tab_has_next(spaces_tab_info);
spaces_tab_info.cur_stack = cur_stack_old;
}
}
} // namespace TemplatesFunctions
} // namespace Winix