/*
* Copyright 2005, 2006, 2007 Florian Schmitz
*
* This file is part of CSSTidy.
*
* CSSTidy is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* CSSTidy is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*/
#include "csspp_globals.hpp"
using namespace std;
string csstidy::_htmlsp(const string istring, const bool plain)
{
if (!plain) {
return htmlspecialchars(istring);
}
return istring;
}
void csstidy::_convert_raw_css()
{
csstokens = vector();
for (css_struct::iterator i = css.begin(); i != css.end(); ++i)
{
if (settings["sort_selectors"]) i->second.sort();
if (i->first != "standard") {
add_token(AT_START, i->first, true);
}
for(sstore::iterator j = i->second.begin(); j != i->second.end(); ++j)
{
if (settings["sort_properties"]) j->second.sort();
add_token(SEL_START, j->first, true);
for(umap::iterator k = j->second.begin(); k != j->second.end(); ++k)
{
add_token(PROPERTY, k->first, true);
add_token(VALUE, k->second, true);
}
add_token(SEL_END, j->first, true);
}
if (i->first != "standard") {
add_token(AT_END, i->first, true);
}
}
}
int csstidy::_seeknocomment(const int key, int move)
{
int go = (move > 0) ? 1 : -1;
for (int i = key + 1; abs(key-i)-1 < abs(move); i += go) {
if (i < 0 || i > csstokens.size()) {
return -1;
}
if (csstokens[i].type == COMMENT) {
move += 1;
continue;
}
return csstokens[i].type;
}
}
void csstidy::print_css(string filename)
{
if(css.empty() && charset == "" && namesp == "" && import.empty() && csstokens.empty())
{
if(!settings["silent"]) cout << "Warning: empty CSS output!" << endl;
}
ofstream file_output;
if(filename != "")
{
file_output.open(filename.c_str(),ios::binary);
if(file_output.bad())
{
if(!settings["silent"]) cout << "Error when trying to save the output file!" << endl;
return;
}
}
if(!settings["preserve_css"]) {
_convert_raw_css();
}
if(!settings["allow_html_in_templates"])
{
for(int i = 0; i < csstemplate.size(); ++i)
{
csstemplate[i] = strip_tags(csstemplate[i]);
}
}
stringstream output, in_at_out;
if (settings["timestamp"]) {
time_t rawtime;
time(&rawtime);
token temp;
temp.data = " CSSTidy ";
temp.data += CSSTIDY_VERSION;
temp.data += ": " + rtrim(asctime (localtime ( &rawtime ))) + " ";
temp.type = COMMENT;
csstokens.insert(csstokens.begin(), temp);
}
if(charset != "")
{
output << csstemplate[0] << "@charset " << csstemplate[5] << charset << csstemplate[6];
}
if(import.size() > 0)
{
for(int i = 0; i < import.size(); i ++)
{
output << csstemplate[0] << "@import " << csstemplate[5] << import[i] << csstemplate[6];
}
}
if(namesp != "")
{
output << csstemplate[0] << "@namespace " << csstemplate[5] << namesp << csstemplate[6];
}
output << csstemplate[13];
stringstream* out =& output;
bool plain = !settings["allow_html_in_templates"];
for (int i = 0; i < csstokens.size(); ++i)
{
switch (csstokens[i].type)
{
case AT_START:
*out << csstemplate[0] << _htmlsp(csstokens[i].data, plain) + csstemplate[1];
out =& in_at_out;
break;
case SEL_START:
if(settings["lowercase_s"]) csstokens[i].data = strtolower(csstokens[i].data);
*out << ((csstokens[i].data[0] != '@') ? csstemplate[2] + _htmlsp(csstokens[i].data, plain) : csstemplate[0] + _htmlsp(csstokens[i].data, plain));
*out << csstemplate[3];
break;
case PROPERTY:
if(settings["case_properties"] == 2) csstokens[i].data = strtoupper(csstokens[i].data);
if(settings["case_properties"] == 1) csstokens[i].data = strtolower(csstokens[i].data);
*out << csstemplate[4] << _htmlsp(csstokens[i].data, plain) << ":" << csstemplate[5];
break;
case VALUE:
*out << _htmlsp(csstokens[i].data, plain);
if(_seeknocomment(i, 1) == SEL_END && settings["remove_last_semicolon"]) {
*out << str_replace(";", "", csstemplate[6]);
} else {
*out << csstemplate[6];
}
break;
case SEL_END:
*out << csstemplate[7];
if(_seeknocomment(i, 1) != AT_END) *out << csstemplate[8];
break;
case AT_END:
out =& output;
*out << csstemplate[10] << str_replace("\n", "\n" + csstemplate[10], in_at_out.str());
in_at_out.str("");
*out << csstemplate[9];
break;
case COMMENT:
*out << csstemplate[11] << "/*" << _htmlsp(csstokens[i].data, plain) << "*/" << csstemplate[12];
break;
}
}
string output_string = trim(output.str());
if(!settings["silent"]) {
cout << endl << "Selectors: " << selectors << " | Properties: " << properties << endl;
float ratio = round(((input_size - (float) output_string.length())/input_size)*100,2);
float i_b = round(((float) input_size)/1024,3);
float o_b = round(((float) output_string.length())/1024,3);
cout << "Input size: " << i_b << "KiB Output size: " << o_b << "KiB Compression ratio: " << ratio << "%" << endl;
}
if(filename == "")
{
if(!settings["silent"]) cout << "-----------------------------------\n\n";
cout << output_string << "\n";
}
else
{
file_output << output_string;
}
if(logs.size() > 0 && !settings["silent"])
{
cout << "-----------------------------------\n\n";
for(map >::iterator j = logs.begin(); j != logs.end(); j++ )
{
for(int i = 0; i < j->second.size(); ++i)
{
cout << j->first << ": " << j->second[i].m << "\n" ;
}
}
}
if(!settings["silent"]) {
cout << "\n-----------------------------------" << endl << "CSSTidy " << CSSTIDY_VERSION << " by Florian Schmitz 2005, 2006" << endl;
}
file_output.close();
}