cdesktopenv/cde/programs/dtdocbook/infolib/StyleTask.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;
}