/* * 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 #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 *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(hash_func); f_buffer = NULL; f_pathbuf = NULL; f_locator = NULL; f_dataMode = inPath; feature_depth = new Stack; } 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; 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; }