589 lines
13 KiB
C
589 lines
13 KiB
C
/*
|
|
* CDE - Common Desktop Environment
|
|
*
|
|
* Copyright (c) 1993-2012, The Open Group. All rights reserved.
|
|
*
|
|
* These libraries and programs are free software; you can
|
|
* redistribute them and/or modify them under the terms of the GNU
|
|
* Lesser General Public License as published by the Free Software
|
|
* Foundation; either version 2 of the License, or (at your option)
|
|
* any later version.
|
|
*
|
|
* These libraries and programs are distributed in the hope that
|
|
* they 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 these libraries and programs; if not, write
|
|
* to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
|
|
* Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
/* $XConsortium: StyleTask.cc /main/7 1996/07/18 15:20:02 drk $ */
|
|
/* $XConsortium: StyleTask.cc /main/7 1996/07/18 15:20:02 drk $ */
|
|
/* $XConsortium: StyleTask.cc /main/7 1996/07/18 15:20:02 drk $ */
|
|
/* $XConsortium: StyleTask.cc /main/7 1996/07/18 15:20:02 drk $ */
|
|
/* $XConsortium: StyleTask.cc /main/7 1996/07/18 15:20:02 drk $ */
|
|
/* $XConsortium: StyleTask.cc /main/7 1996/07/18 15:20:02 drk $ */
|
|
/* $XConsortium: StyleTask.cc /main/7 1996/07/18 15:20:02 drk $ */
|
|
/* export... */
|
|
#include "StyleTask.h"
|
|
|
|
/* import... */
|
|
#include <assert.h>
|
|
|
|
#include "AttributeRec.h"
|
|
#include "DataBase.h"
|
|
#include "FlexBuffer.h"
|
|
#include "OLAF.h"
|
|
#include "OL_Data.h"
|
|
#include "SGMLName.h"
|
|
#include "StringList.h"
|
|
#include "Token.h"
|
|
|
|
#ifdef FISH_DEBUG
|
|
#include "dbug.h" /* Fred Fish's dbug.h */
|
|
#endif
|
|
|
|
/*****************
|
|
*
|
|
* StyleTask
|
|
*
|
|
*****************/
|
|
|
|
static unsigned hash_func(const CC_String &str)
|
|
{
|
|
return str.hash();
|
|
}
|
|
|
|
inline
|
|
static
|
|
void write_tabs( FlexBuffer *buf, Stack<int> *fstack, char ch )
|
|
{
|
|
int num_ch = fstack->entries() + 1;
|
|
|
|
for ( int i=0; i < num_ch; i++ ) {
|
|
buf->put(ch);
|
|
}
|
|
}
|
|
|
|
|
|
StyleTask::StyleTask()
|
|
{
|
|
f_base = f_select = -1;
|
|
onlineSS = new FlexBuffer();
|
|
printSS = new FlexBuffer();
|
|
viewset = new hashTable<CC_String,int>(hash_func);
|
|
f_buffer = NULL;
|
|
f_pathbuf = NULL;
|
|
f_locator = NULL;
|
|
f_dataMode = inPath;
|
|
|
|
feature_depth = new Stack<int>;
|
|
|
|
}
|
|
|
|
|
|
StyleTask::~StyleTask()
|
|
{
|
|
delete viewset;
|
|
delete f_pathbuf;
|
|
delete onlineSS;
|
|
delete printSS;
|
|
delete feature_depth;
|
|
|
|
KILLSUBTASK(f_locator);
|
|
|
|
ComplexTask::removeAllSubTasks();
|
|
}
|
|
|
|
void StyleTask::reset()
|
|
{
|
|
f_base = f_select = -1;
|
|
delete f_pathbuf; f_pathbuf = NULL;
|
|
delete onlineSS; onlineSS = new FlexBuffer();
|
|
delete printSS; printSS = new FlexBuffer();
|
|
delete feature_depth;
|
|
feature_depth = new Stack<int>;
|
|
f_buffer = NULL;
|
|
|
|
KILLSUBTASK( f_locator );
|
|
|
|
ComplexTask::removeAllSubTasks();
|
|
|
|
}
|
|
|
|
|
|
static void
|
|
report_position(FlexBuffer *buffer, const char *file, int line)
|
|
{
|
|
char info[200]; //MAGIC
|
|
|
|
snprintf(info, sizeof(info), "#file: %.150s line: %d\n", file, line);
|
|
buffer->writeStr(info);
|
|
}
|
|
|
|
|
|
static void
|
|
write_array(FlexBuffer *buffer, const char *tokens, int quotes)
|
|
{
|
|
buffer->put('[');
|
|
|
|
char *str = strdup ( tokens );
|
|
|
|
if(str){
|
|
char * token = strtok ( str, " \n\t");
|
|
if ( token ) {
|
|
if (quotes) buffer->put( '\"' );
|
|
buffer->writeStr( token );
|
|
if (quotes) buffer->put( '\"' );
|
|
|
|
while ( (token = strtok ( NULL, " \n\t" )) ) {
|
|
buffer->put(',');
|
|
if (quotes) buffer->put( '\"' );
|
|
buffer->writeStr( token );
|
|
if (quotes) buffer->put( '\"' );
|
|
}
|
|
}
|
|
free(str);
|
|
} /*@# else out of memory... */
|
|
|
|
buffer->put(']');
|
|
}
|
|
|
|
|
|
static void
|
|
autonumber(FlexBuffer *buffer, const Token& t)
|
|
{
|
|
const AttributeRec *id = t.LookupAttr(SGMLName::intern("ID", 1));
|
|
const AttributeRec *type = t.LookupAttr(SGMLName::intern("Type", 1));
|
|
const AttributeRec *initial = t.LookupAttr(SGMLName::intern("Initial", 1));
|
|
const AttributeRec *delta = t.LookupAttr(SGMLName::intern("Delta", 1));
|
|
const AttributeRec *reset = t.LookupAttr(SGMLName::intern("Reset", 1));
|
|
const AttributeRec *counter = t.LookupAttr(SGMLName::intern("Counter", 1));
|
|
|
|
if(!id) throw(Unexpected("Autonumber: missing ID attribute"));
|
|
if(!type) throw(Unexpected("Autonumber: missing Type attribute"));
|
|
if(!initial) throw(Unexpected("Autonumber: missing Initial attribute"));
|
|
if(!delta) throw(Unexpected("Autonumber: missing Delta attribute"));
|
|
if(!reset) throw(Unexpected("Autonumber: missing Reset attribute"));
|
|
if(!counter) throw(Unexpected("Autonumber: missing Counter attribute"));
|
|
|
|
|
|
buffer->writeStr(id->getAttrValueString());
|
|
buffer->writeStr(" = autonumber[\"");
|
|
buffer->writeStr(type->getAttrValueString());
|
|
buffer->writeStr("\", \"");
|
|
buffer->writeStr(initial->getAttrValueString());
|
|
buffer->writeStr("\", \"");
|
|
buffer->writeStr(delta->getAttrValueString());
|
|
buffer->writeStr("\", ");
|
|
|
|
write_array(buffer, counter->getAttrValueString(), 1);
|
|
|
|
buffer->writeStr(", ");
|
|
|
|
write_array(buffer, reset->getAttrValueString(), 1);
|
|
|
|
buffer->writeStr("]\n\n");
|
|
}
|
|
|
|
|
|
static void
|
|
write_attr(FlexBuffer *f_buffer, const AttributeRec *arec)
|
|
{
|
|
f_buffer->writeStr( SGMLName::lookup( arec->getAttrName() ) );
|
|
f_buffer->writeStr( ":\t" );
|
|
|
|
const char *val = arec->getAttrValueString();
|
|
|
|
/* NAMES, NUMBERS convert to arrays for stylesheet lang. */
|
|
if(arec->getAttrType() == SGMLName::TOKEN
|
|
&& strchr(val, ' ')){
|
|
write_array(f_buffer, val, 0);
|
|
}else{
|
|
/* NASTY HACK!
|
|
* The stylesheet internal language requires some feature
|
|
* values to be quoted, and some not. It _seems_ that
|
|
* quoting anything that doesn't start with a digit will
|
|
* satisfy the constraints. This is highly artificial!
|
|
*
|
|
* Now for the exception that proves the hack!
|
|
* TRUE and FALSE...
|
|
*
|
|
* One more to add to the heap,
|
|
* if an attribute value is being referenced
|
|
*/
|
|
|
|
int quotes = !isdigit(val[0])
|
|
&& strcmp(val, "TRUE") != 0
|
|
&& strcmp(val, "FALSE") != 0
|
|
&& val[0] != '@';
|
|
|
|
if(quotes) f_buffer->writeStr( "\"" );
|
|
f_buffer->writeStr( val );
|
|
if(quotes) f_buffer->writeStr( "\"" );
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
StyleTask::markup( const Token &t )
|
|
{
|
|
ComplexTask::markup(t);
|
|
|
|
if (t.type() == START) {
|
|
/*
|
|
* Process Stylesheet start tags...
|
|
*/
|
|
|
|
switch(t.olaf()){
|
|
case OLAF::Stylesheet:
|
|
|
|
if (f_base >= 0) {
|
|
throw
|
|
(Unexpected
|
|
("illegal nested STYLESHEET architectural form"));
|
|
}
|
|
|
|
f_base = t.level();
|
|
#ifdef FISH_DEBUG
|
|
DBUG_PRINT("Style", ("Style level=`%d'\n", f_base));
|
|
#endif
|
|
break;
|
|
|
|
case OLAF::Path:
|
|
|
|
if ( f_pathbuf != NULL ) {
|
|
delete f_pathbuf;
|
|
}
|
|
|
|
f_pathbuf = new FlexBuffer();
|
|
f_buffer = f_pathbuf;
|
|
f_dataMode = inPath;
|
|
break;
|
|
|
|
case OLAF::Select:
|
|
f_buffer->writeStr( "[" );
|
|
f_select = t.level();
|
|
break;
|
|
|
|
case OLAF::Online:
|
|
|
|
f_buffer = onlineSS;
|
|
// feature_depth->clear();
|
|
|
|
if ( f_pathbuf == NULL ) {
|
|
throw(Unexpected("no path available for online feature."));
|
|
}
|
|
|
|
report_position(f_buffer, t.file(), t.line());
|
|
|
|
f_buffer->writeStr( f_pathbuf->GetBuffer() );
|
|
f_buffer->writeStr( "\n" );
|
|
write_tabs( f_buffer, feature_depth, '\t');
|
|
f_buffer->writeStr( "{\n" );
|
|
feature_depth->push(t.level());
|
|
|
|
break;
|
|
|
|
case OLAF::Print:
|
|
|
|
f_buffer = printSS;
|
|
// feature_depth->clear();
|
|
|
|
if ( f_pathbuf == NULL ) {
|
|
throw(Unexpected("no path available for print feature."));
|
|
}
|
|
|
|
report_position(f_buffer, t.file(), t.line());
|
|
f_buffer->writeStr( f_pathbuf->GetBuffer() );
|
|
f_buffer->writeStr( "\n" );
|
|
write_tabs( f_buffer, feature_depth, '\t');
|
|
f_buffer->writeStr( "{\n" );
|
|
feature_depth->push( t.level() );
|
|
|
|
break;
|
|
|
|
case OLAF::AutoNumber:
|
|
|
|
report_position(onlineSS, t.file(), t.line());
|
|
autonumber(onlineSS, t);
|
|
|
|
report_position(printSS, t.file(), t.line());
|
|
autonumber(printSS, t);
|
|
break;
|
|
|
|
case OLAF::FeatureText:
|
|
|
|
report_position(f_buffer, t.file(), t.line());
|
|
write_tabs( f_buffer, feature_depth, '\t');
|
|
|
|
f_buffer->writeStr( t.giName() );
|
|
f_buffer->writeStr( ": " );
|
|
f_dataMode = startContent;
|
|
break;
|
|
|
|
|
|
case OLAF::AutoRef:
|
|
{
|
|
const AttributeRec *arec;
|
|
int id = SGMLName::intern("ID");
|
|
if((arec = t.LookupAttr(id))){
|
|
|
|
if(f_dataMode == inContent){
|
|
f_buffer->writeStr(" + ");
|
|
}
|
|
|
|
f_buffer->writeStr(arec->getAttrValueString());
|
|
f_dataMode = inContent;
|
|
} /* else document is not conforming... sgmls will report error */
|
|
}
|
|
break;
|
|
|
|
case OLAF::Feature:
|
|
|
|
report_position(f_buffer, t.file(), t.line());
|
|
write_tabs( f_buffer, feature_depth, '\t');
|
|
|
|
f_buffer->writeStr( t.giName() );
|
|
f_buffer->writeStr( ": " );
|
|
|
|
const AttributeRec *arec;
|
|
|
|
/*
|
|
* Is it an enumeration feature?
|
|
*/
|
|
if((arec = t.LookupAttr(OLAF::OL_Choice))){
|
|
|
|
/* OL_Choice can only be applied to NAME attributes, hence
|
|
we don't neet to worryabout "'s in the attribute value.
|
|
*/
|
|
/* except TRUE and FALSE....*/
|
|
|
|
const char *val = arec->getAttrValueString();
|
|
|
|
int quotes = !isdigit(val[0])
|
|
&& strcmp(val, "TRUE") != 0
|
|
&& strcmp(val, "FALSE") != 0
|
|
&& val[0] != '@';
|
|
|
|
if (quotes) f_buffer->writeStr("\"");
|
|
f_buffer->writeStr(val);
|
|
if (quotes) f_buffer->writeStr("\" ");
|
|
|
|
}else{
|
|
f_buffer->writeStr( " {\n" );
|
|
|
|
for (arec = t.GetFirstAttr();
|
|
arec != NULL;
|
|
arec = t.GetNextAttr( arec )) {
|
|
|
|
if (( arec->getAttrValueString() != NULL ) &&
|
|
( arec->getAttrName() != OLAF::OLIAS )) {
|
|
|
|
write_tabs( f_buffer, feature_depth, '\t');
|
|
f_buffer->put('\t');
|
|
|
|
write_attr(f_buffer, arec);
|
|
|
|
f_buffer->writeStr( ",\n" );
|
|
}
|
|
}
|
|
feature_depth->push(t.level());
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
/*
|
|
* first time we see OL-ID="...", spawn an OL_Data to collect the id
|
|
*/
|
|
if ((f_base >= 0) && (f_locator == NULL) &&
|
|
(t.LookupAttr(OLAF::OL_id))) {
|
|
|
|
#ifdef FISH_DEBUG
|
|
DBUG_PRINT("Style", ("spawning locator collection subtask\n"));
|
|
#endif
|
|
f_locator = new OL_Data(t, OLAF::OL_id, REMOVE_SPACES);
|
|
addSubTask( f_locator );
|
|
|
|
}
|
|
}
|
|
|
|
else if (t.type() == END) {
|
|
|
|
if (f_base > 0) {
|
|
|
|
int topelement;
|
|
if ( !feature_depth->empty() ) {
|
|
if ( (topelement = feature_depth->top()) ) {
|
|
if ( topelement == t.level() ) {
|
|
topelement = feature_depth->pop();
|
|
write_tabs( f_buffer, feature_depth, '\t');
|
|
|
|
if(feature_depth->empty()){
|
|
f_buffer->writeStr("}\n");
|
|
}
|
|
else {
|
|
f_buffer->writeStr("},\n");
|
|
}
|
|
|
|
}else if ( topelement + 1 == t.level() ) {
|
|
/* need a new-line at end of FeatureText data */
|
|
f_buffer->writeStr(",\n");
|
|
}
|
|
}
|
|
}
|
|
|
|
if (t.level() == f_base) {
|
|
/* found end of stylesheet... write out StyleSheet data */
|
|
#ifdef FISH_DEBUG
|
|
DBUG_PRINT("Style", ("found end of stylesheet write out StyleSheet data\n"));
|
|
#endif
|
|
write_record();
|
|
|
|
}
|
|
else if(t.level() == f_select){
|
|
f_buffer->writeStr( "]" );
|
|
f_select = -1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void StyleTask::data ( const char *str, size_t t )
|
|
{
|
|
|
|
if ( f_base > 0 ) {
|
|
|
|
ComplexTask::data( str, t );
|
|
if (f_buffer != NULL) {
|
|
|
|
switch(f_dataMode){
|
|
case inPath:
|
|
f_buffer->write ( str, t );
|
|
break;
|
|
|
|
case inContent:
|
|
f_buffer->write ( " + ", 3 );
|
|
/* fall through */
|
|
|
|
case startContent:
|
|
f_buffer->write ( "\"", 1 );
|
|
f_dataMode = inContent;
|
|
|
|
const char *p;
|
|
for(p = str; *p; p++){
|
|
if(*p == '"' || *p == '\\')
|
|
f_buffer->put('\\');
|
|
f_buffer->put(*p);
|
|
}
|
|
|
|
f_buffer->write ( "\"", 1 );
|
|
break;
|
|
}
|
|
|
|
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
const char *
|
|
StyleTask::locator()
|
|
{
|
|
const char *ret = 0;
|
|
|
|
if (f_locator){
|
|
ret = f_locator->content();
|
|
}
|
|
|
|
if (!(ret && *ret)){
|
|
throw(Unexpected ("No name given to stylesheet."));
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
|
|
void StyleTask::write_record( void )
|
|
{
|
|
|
|
const char
|
|
*localstr = locator();
|
|
|
|
#ifdef FISH_DEBUG
|
|
DBUG_PRINT("Style",
|
|
("Style Sheet: \nview=`%s'\nonlineSS=`%s'\n\nprintSS=`%s'\n",
|
|
localstr,
|
|
onlineSS->GetBuffer(),
|
|
printSS->GetBuffer() ));
|
|
|
|
DBUG_PRINT("Style", ("View id...\n"));
|
|
DBUG_PRINT("Style", ("\tis: `%s'\n", localstr ));
|
|
#endif
|
|
|
|
CC_String *str = new CC_String( localstr );
|
|
int *bogus = new int(0);
|
|
if ( !viewset->contains( str ) ) {
|
|
viewset->insertKeyAndValue( str,bogus );
|
|
}
|
|
else {
|
|
Token::signalError(Token::User, Token::Continuable, 0, 0,
|
|
"Duplicate stylesheet id `%s'", localstr);
|
|
delete bogus;
|
|
return;
|
|
}
|
|
|
|
int online_bufsize=onlineSS->GetSize();
|
|
const char *online_buf = onlineSS->GetBuffer();
|
|
|
|
int print_bufsize= printSS->GetSize();
|
|
const char *print_buf = printSS->GetBuffer();
|
|
|
|
done(localstr,
|
|
online_buf, online_bufsize,
|
|
print_buf, print_bufsize);
|
|
}
|
|
|
|
|
|
int StyleTask::exist( const char * str )
|
|
{
|
|
CC_String tmp(str);
|
|
return( viewset->contains( &tmp ) );
|
|
}
|
|
|
|
const char *
|
|
StyleTask::print()
|
|
{
|
|
const char *ret = 0;
|
|
|
|
if(printSS) ret = printSS->GetBuffer();
|
|
|
|
return ret;
|
|
}
|
|
|
|
int
|
|
StyleTask::print_data_size()
|
|
{
|
|
if (printSS) return ( printSS->GetSize() );
|
|
else return 0;
|
|
}
|
|
|
|
const char *
|
|
StyleTask::online()
|
|
{
|
|
return onlineSS->GetBuffer();
|
|
}
|
|
|
|
int
|
|
StyleTask::online_data_size()
|
|
{
|
|
if ( onlineSS ) return ( onlineSS->GetSize() );
|
|
else return 0;
|
|
}
|
|
|