// Copyright 1998,1999 Zanshin Inc.
// The contents of this file are subject to the Zanshin Public License Version
// 1.0 (the "License"); you may not use this file except in compliance with the
// License. You should have received a copy of the License with Latte; see
// the file COPYING. You may also obtain a copy of the License at
// .
//
// Software distributed under the License is distributed on an "AS IS" basis,
// WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
// for the specific language governing rights and limitations under the
// License.
//
// The Original Code is Latte.
//
// The Initial Developer of the Original Code is Zanshin, Inc.
#include
#include
#include
#include
#include
#include
using namespace std;
static bool in_pre = 0;
static unsigned int left_margin = 0;
void
LatteText_PreObj::visit(Latte_Visitor &visitor)
{
Restorer in_pre_restorer(in_pre);
in_pre = 1;
nested_obj()->visit(visitor);
}
Refcounter
LatteText_PreObj::do_eval(Latte_Activation &activation)
{
if (self_evaluating())
return Refcounter(this);
return Refcounter(new
LatteText_PreObj(*(nested_obj()->eval(activation))));
}
void
LatteText_IndentObj::visit(Latte_Visitor &visitor)
{
Restorer left_margin_restorer(left_margin);
left_margin += m_level;
nested_obj()->visit(visitor);
}
Refcounter
LatteText_IndentObj::do_eval(Latte_Activation &activation)
{
if (self_evaluating())
return Refcounter(this);
return Refcounter(new
LatteText_IndentObj(*(nested_obj()->eval(activation))));
}
class PreOp : public Latte_Operator {
public:
const shstring &name() const { static const shstring n = "_pre"; return n; }
protected:
Refcounter apply(const Latte_Wstate &wstate,
const Latte_FileLoc &fileloc,
const Latte_List::const_iterator &args,
const Latte_List::const_iterator &args_end,
Latte_Activation &activation) const {
Refcounter result_list(new Latte_List);
for (Latte_List::const_iterator i = args; i != args_end; ++i)
result_list->push_back((*i)->eval(activation));
return Refcounter(new
LatteText_PreObj(*(Latte_WsNode::wrap(*result_list,
wstate))));
}
};
class IndentOp : public Latte_Operator {
public:
const shstring &name() const {
static const shstring n = "_indent";
return n;
}
protected:
Refcounter apply(const Latte_Wstate &wstate,
const Latte_FileLoc &fileloc,
const Latte_List::const_iterator &args,
const Latte_List::const_iterator &args_end,
Latte_Activation &activation) const {
Refcounter result_list(new Latte_List);
Refcounter level_arg;
for (Latte_List::const_iterator i = args; i != args_end; ++i) {
if ((*i)->as_assignment()) {
const Latte_Assignment *assignment = (*i)->as_assignment();
if (assignment->name().str().compare("level") == 0)
level_arg = assignment->nested_obj();
else
throw IllegalAssignment(*this, assignment->name(), fileloc);
} else
result_list->push_back((*i)->eval(activation));
}
unsigned int level = 2;
if (level_arg.get()) {
Refcounter level_val = level_arg->eval(activation);
level = static_cast(level_val->numeric_val());
}
return Refcounter(new
LatteText_IndentObj(*(Latte_WsNode::wrap(*result_list,
wstate)),
level));
}
};
void
LatteText_TextVisitor::visit_str(Latte_Str &str)
{
Latte_Wstate ws = suggest_wstate(str.wstate());
static bool ever_called = 0;
if (in_pre) {
cout << ws;
if (ws.newlines() > 0)
m_column = 0;
m_column += ws.spaces();
} else if (ws.newlines() > 1) {
if (ever_called)
m_out << endl << endl;
m_column = 0;
} else if (ws.newlines() == 1) {
ws = Latte_Wstate();
ws.space(m_new_sentence ? 2 : 1);
}
ever_called = 1;
m_new_sentence = 0;
if (m_sentence_end_chars) {
shstring::const_iterator p = str.end();
do {
--p;
if (!m_sentence_end_transparent_chars
|| !strchr(m_sentence_end_transparent_chars, *p)) {
if (strchr(m_sentence_end_chars, *p))
m_new_sentence = 1;
break;
}
} while (p != str.begin());
}
if (!in_pre && (m_column > left_margin)) {
unsigned int new_column = m_column + ws.spaces();
new_column += str.size();
if (new_column < m_wrapcol) {
m_out << ws << str.str();
m_column = new_column;
return;
}
m_out << endl;
m_column = 0;
}
// in_pre || (m_column == 0)
while (m_column < left_margin) {
m_out << ' ';
++m_column;
}
m_out << str.str();
m_column += str.size();
}
void
latte_text(bool no_default,
unsigned long log_flags,
const deque::const_iterator &loads_begin,
const deque::const_iterator &loads_end,
unsigned int wrapcol,
const char *sentence_end_chars,
const char *sentence_end_transparent_chars,
const char *filename, istream &in, ostream &out)
{
srandom(getpid() ^ time(0)); // should the UI do this?
latte_init(1);
Latte_Reader reader(in, filename);
latte_log_flags = log_flags;
reader.install_standard_definitions();
reader.define_global("__FILE__",
Refcounter(new
Latte_Str(Latte_Wstate(),
Latte_FileLoc(),
filename)));
reader.define_global("_pre", Refcounter(new PreOp));
reader.define_global("_indent", Refcounter(new IndentOp));
if (!no_default) {
latte_load_library("standard", reader.global_activation());
latte_load_library("text", reader.global_activation());
}
for (deque::const_iterator i = loads_begin;
i != loads_end;
++i)
latte_load_library(*i, reader.global_activation());
LatteText_TextVisitor visitor(out, wrapcol,
sentence_end_chars,
sentence_end_transparent_chars);
reader.process(visitor);
#if 0
if (!reader.processed()) {
const Latte_Obj &unprocessed = reader.unprocessed();
const Latte_Tangible *tangible = unprocessed.as_tangible();
const Latte_Group *group = unprocessed.as_group();
const Latte_Assignment *assignment = unprocessed.as_assignment();
if (group)
throw Latte_Reader::IncompleteGroup(group->fileloc());
if (assignment)
throw Latte_Reader::IncompleteAssignment(assignment->fileloc());
if (tangible)
throw Latte_Reader::Incomplete(tangible->fileloc());
throw Latte_Reader::Incomplete(Latte_FileLoc());
}
#endif
out << endl;
}