/** GSWTemplateParser.m - GSWeb: Class GSWTemplateParser Copyright (C) 1999-2004 Free Software Foundation, Inc. Written by: Manuel Guesdon Date: Mar 1999 $Revision$ $Date$ $Id$ This file is part of the GNUstep Web Library. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. **/ #include "config.h" RCS_ID("$Id$") #include "GSWeb.h" //==================================================================== @implementation GSWTemplateParser //-------------------------------------------------------------------- +(void)initialize { if (self == [GSWTemplateParser class]) { }; }; //-------------------------------------------------------------------- +(GSWTemplateParserType)templateParserTypeFromString:(NSString*)string { GSWTemplateParserType type=0; if ([string caseInsensitiveCompare:GSWOPTValue_DefaultTemplateParser_RawHTML] == NSOrderedSame) type=GSWTemplateParserType_RawHTML; else if ([string caseInsensitiveCompare:GSWOPTValue_DefaultTemplateParser_XMLHTML] == NSOrderedSame) { NSWarnLog(@"XMLHTL parser is no more handled. Using RawHTML one"); type=GSWTemplateParserType_RawHTML; } else if ([string caseInsensitiveCompare:GSWOPTValue_DefaultTemplateParser_XMLHTMLNoOmittedTags] == NSOrderedSame) { NSWarnLog(@"XMLHTMLNoOmittedTags parser is no more handled. Using RawHTML one"); type=GSWTemplateParserType_RawHTML; } else if ([string caseInsensitiveCompare:GSWOPTValue_DefaultTemplateParser_XML] == NSOrderedSame) { NSWarnLog(@"XML parser is no more handled. Using RawHTML one"); type=GSWTemplateParserType_RawHTML; } else if ([string caseInsensitiveCompare:GSWOPTValue_DefaultTemplateParser_ANTLR] == NSOrderedSame) { NSWarnLog(@"ANTLR parser is no more handled. Using RawHTML one"); type=GSWTemplateParserType_RawHTML; } else type=GSWTemplateParserType_RawHTML; NSDebugMLog(@"templateParserTypeFromString:%@ ==> %d",string,type); return type; } //-------------------------------------------------------------------- +(GSWTemplateParserType)defaultTemplateParserType { return [self templateParserTypeFromString:[GSWApplication defaultTemplateParser]]; } //-------------------------------------------------------------------- +(GSWElement*)templateWithHTMLString:(NSString *)HTMLString declarationString:(NSString *)declarationsString languages:(NSArray *)languages { return [self templateNamed: nil inFrameworkNamed: nil withParserType: [self defaultTemplateParserType] parserClassName: nil withString: HTMLString encoding: GSUndefinedEncoding fromPath: nil declarationsString: declarationsString languages: languages declarationsPath: nil]; } //-------------------------------------------------------------------- +(GSWElement*)templateNamed:(NSString*)aName inFrameworkNamed:(NSString*)aFrameworkName withParserType:(GSWTemplateParserType)parserType parserClassName:(NSString*)parserClassName withString:(NSString*)HTMLString encoding:(NSStringEncoding)anEncoding fromPath:(NSString*)HTMLPath declarationsString:(NSString*)declarationsString languages:(NSArray*)someLanguages declarationsPath:(NSString*)aDeclarationsPath { GSWElement* resultTemplate=nil; Class parserClass=Nil; LOGClassFnStart(); NSDebugMLLog(@"GSWTemplateParser",@"aDeclarationsPath=%@",aDeclarationsPath); if (parserClassName) { parserClass=NSClassFromString(parserClassName); NSAssert1(parserClass,@"No Parser class named %@",parserClassName); }; resultTemplate=[self templateNamed:aName inFrameworkNamed:aFrameworkName withParserType:(GSWTemplateParserType)parserType parserClass:parserClass withString:HTMLString encoding:anEncoding fromPath:HTMLPath declarationsString:declarationsString languages:someLanguages declarationsPath:aDeclarationsPath]; LOGClassFnStop(); return resultTemplate; }; //-------------------------------------------------------------------- +(GSWElement*)templateNamed:(NSString*)aName inFrameworkNamed:(NSString*)aFrameworkName withParserType:(GSWTemplateParserType)parserType parserClass:(Class)parserClass withString:(NSString*)HTMLString encoding:(NSStringEncoding)anEncoding fromPath:(NSString*)HTMLPath declarationsString:(NSString*)declarationsString languages:(NSArray*)someLanguages declarationsPath:(NSString*)aDeclarationsPath { GSWElement* resultTemplate=nil; GSWTemplateParser* templateParser=nil; Class finalParserClass=Nil; LOGClassFnStart(); NSDebugMLLog(@"GSWTemplateParser", @"template named:%@ frameworkName:%@ declarationsString=%@", aName,aFrameworkName,declarationsString); NSDebugMLLog(@"GSWTemplateParser", @"aDeclarationsPath=%@",aDeclarationsPath); NSDebugMLLog(@"GSWTemplateParser", @"parserClass:%@ parserType:%d", parserClass,parserType); if (parserClass) finalParserClass=parserClass; else { if (parserType==GSWTemplateParserType_Default) parserType=[self defaultTemplateParserType]; switch(parserType) { case GSWTemplateParserType_XMLHTML: case GSWTemplateParserType_XMLHTMLNoOmittedTags: NSWarnLog(@"XMLHTML parser is no more handled. Using RawHTML one"); finalParserClass=[GSWHTMLTemplateParser class]; break; case GSWTemplateParserType_XML: NSWarnLog(@"XML parser is no more handled. Using RawHTML one"); finalParserClass=[GSWHTMLTemplateParser class]; break; case GSWTemplateParserType_ANTLR: NSWarnLog(@"ANTLR parser is no more handled. Using RawHTML one"); finalParserClass=[GSWHTMLTemplateParser class]; break; case GSWTemplateParserType_RawHTML: finalParserClass=[GSWHTMLTemplateParser class]; break; default: finalParserClass=[GSWHTMLTemplateParser class]; break; }; }; NSDebugMLLog(@"GSWTemplateParser", @"finalParserClass:%@ parserType:%d", finalParserClass,parserType); NSAssert2(finalParserClass,@"No Final Parser class: parserClass:%@ parserType:%d", parserClass,parserType); templateParser=[[[finalParserClass alloc] initWithTemplateName:aName inFrameworkName:aFrameworkName withString:HTMLString encoding:anEncoding fromPath:HTMLPath withDeclarationsString:declarationsString fromPath:aDeclarationsPath forLanguages:someLanguages] autorelease]; if (templateParser) { resultTemplate=[templateParser template]; }; LOGClassFnStop(); return resultTemplate; }; //-------------------------------------------------------------------- -(id)initWithTemplateName:(NSString*)aName inFrameworkName:(NSString*)aFrameworkName withString:(NSString*)HTMLString encoding:(NSStringEncoding)anEncoding fromPath:(NSString*)HTMLPath withDeclarationsString:(NSString*)declarationsString fromPath:(NSString*)aDeclarationsPath forLanguages:(NSArray*)someLanguages { if ((self=[self init])) { ASSIGN(_templateName,aName); ASSIGN(_frameworkName,aFrameworkName); ASSIGN(_string,HTMLString); _stringEncoding=anEncoding; ASSIGN(_stringPath,HTMLPath); ASSIGN(_declarationsString,declarationsString); ASSIGN(_languages,someLanguages); ASSIGN(_declarationsFilePath,aDeclarationsPath); }; return self; }; //-------------------------------------------------------------------- -(void)dealloc { DESTROY(_templateName); DESTROY(_frameworkName); DESTROY(_string); DESTROY(_stringPath); DESTROY(_declarationsString); DESTROY(_languages); DESTROY(_declarationsFilePath); DESTROY(_processedDeclarationsFilePaths); DESTROY(_template); DESTROY(_declarations); DESTROY(_errorMessages); [super dealloc]; }; //-------------------------------------------------------------------- -(NSString*)logPrefix { return [NSString stringWithFormat:@"%@:Template Parser for template named %@ in framework %@ \nat %@ - ", NSStringFromClass(isa), _templateName, _frameworkName, _stringPath]; }; //-------------------------------------------------------------------- -(void)addErrorMessage:(NSString*)errorMessage { if (!_errorMessages) _errorMessages=(NSMutableArray*)[NSMutableArray new]; [_errorMessages addObject:[NSString stringWithFormat:@"%@%@", [self logPrefix], errorMessage]]; }; //-------------------------------------------------------------------- -(void)addErrorMessageFormat:(NSString*)format arguments:(va_list)arguments { NSString* string=[NSString stringWithFormat:format arguments:arguments]; [self addErrorMessage:string]; } //-------------------------------------------------------------------- -(void)addErrorMessageFormat:(NSString*)format,... { va_list ap; va_start(ap,format); [self addErrorMessageFormat:format arguments:ap]; va_end(ap); }; //-------------------------------------------------------------------- -(NSMutableArray*)errorMessages { return _errorMessages; }; //-------------------------------------------------------------------- -(NSString*)errorMessagesAsText { return [[self errorMessages]componentsJoinedByString:@"\n"]; }; //-------------------------------------------------------------------- /** parse the template if it's not done and returns it May raise exception **/ -(GSWElement*)template { LOGObjectFnStart(); if (!_template) { NSArray* elements=nil; NSDictionary* declarations=nil; declarations=[self declarations]; if (!declarations) { ExceptionRaise(@"GSWTemplateParser", @"%@ Can't get declarations", [self logPrefix]); } else { /* NSMutableArray* _classes=[NSMutableArray array]; BOOL createClassesOk=NO; NSEnumerator* _enum = [declarationsElements objectEnumerator]; id _obj=nil; NSString* _className=nil; NSDebugMLLog(@"GSWTemplateParser",@"template named:%@ declarationsElements=%@",aName,declarationsElements); while ((_obj = [_enum nextObject])) { _className=[_obj className]; if (_className) [_classes addObject:_className]; }; createClassesOk=YES;/[GSWApplication createUnknownComponentClasses:_classes superClassName:@"GSWComponent"]; if (createClassesOk) { */ NS_DURING { elements=[self templateElements]; } NS_HANDLER { LOGError(@"%@ Parse failed! Exception:%@", [self logPrefix], localException); localException=ExceptionByAddingUserInfoObjectFrameInfo(localException, @"%@ - In [htmlParser document] Parse failed!", [self logPrefix]); [localException retain]; [localException autorelease]; [localException raise]; } NS_ENDHANDLER; if (elements) { NSRange docTypeRangeStart=NSMakeRange(NSNotFound,0); NSRange docTypeRangeEnd=NSMakeRange(NSNotFound,0); _template=[[GSWHTMLStaticGroup alloc]initWithContentElements:elements]; [_template setDeclarationName:[NSString stringWithFormat:@"Template - %@",_templateName]]; NSDebugMLLog(@"GSWTemplateParser", @"template %p=%@",_template,_template); docTypeRangeStart=[_string rangeOfString:@""]; if (docTypeRangeEnd.length) { if (docTypeRangeStart.location < docTypeRangeEnd.location) { [(GSWHTMLStaticGroup*)_template setDocumentTypeString: [_string substringFromRange: NSMakeRange(docTypeRangeStart.location, docTypeRangeEnd.location - docTypeRangeStart.location + 1)]]; } } } }; }; }; LOGObjectFnStop(); return _template; }; //-------------------------------------------------------------------- -(NSArray*)templateElements { [self subclassResponsibility: _cmd]; return nil; }; //-------------------------------------------------------------------- /** returns declarations from includedFilePath included from declaration file in framework named frameworkName Method for GSWDeclarationParserPragmaDelegate protocol **/ -(NSDictionary*)includedDeclarationsFromFilePath:(NSString*)includedFilePath fromFrameworkNamed:(NSString*)frameworkName { NSDictionary* declarations=nil; NSString* declarationFrameworkName=nil; NSString* declarationFileName=nil; GSWResourceManager* resourceManager=nil; NSString* path=nil; int iLanguage=0; BOOL isPathAlreadyProcessed=NO; LOGObjectFnStart(); NSDebugMLLog(@"GSWTemplateParser", @"Template includedDeclarationsFromFilePath:%@", includedFilePath); resourceManager=[GSWApp resourceManager]; declarationFileName=[includedFilePath lastPathComponent]; declarationFrameworkName=[includedFilePath stringByDeletingLastPathComponent]; NSDebugMLLog(@"gswcomponents", @"Template includedDeclarationsFromFilePath: '%@' declarationFileName=%@", includedFilePath,declarationFileName); NSDebugMLLog(@"gswcomponents", @"Template includedDeclarationsFromFilePath: '%@' declarationFrameworkName=%@", includedFilePath,declarationFrameworkName); if ([declarationFrameworkName length]==0) { declarationFrameworkName=frameworkName; if ([declarationFrameworkName length]==0) { declarationFrameworkName=_frameworkName; }; }; NSDebugMLLog(@"gswcomponents", @"declarationFrameworkName=%@", declarationFrameworkName); for(iLanguage=0;iLanguage<=[_languages count] && !path;iLanguage++) { NSString* language=nil; int iName=0; if (iLanguage<[_languages count]) language=[_languages objectAtIndex:iLanguage]; else language=nil; for(iName=0;!path && iName<2;iName++) { NSString* resourceName=nil; NSString* completeResourceName=nil; resourceName=[declarationFileName stringByAppendingString: GSWPagePSuffix[GSWebNamingConvForRound(iName)]]; completeResourceName=[declarationFileName stringByAppendingString: GSWComponentDeclarationsPSuffix[GSWebNamingConvForRound(iName)]]; NSDebugMLLog(@"gswcomponents", @"resourceName=%@ completeResourceName=%@ declarationFileName=%@", resourceName, completeResourceName, declarationFileName); NSDebugMLLog(@"gswcomponents", @"Search %@ Language=%@",resourceName,language); path=[resourceManager pathForResourceNamed:resourceName inFramework:declarationFrameworkName language:language]; NSDebugMLLog(@"gswcomponents", @"Search In Page Component: language=%@ path=%@ _processedDeclarationsFilePaths=%@", language, path, _processedDeclarationsFilePaths); if (path) { path=[path stringByAppendingPathComponent:completeResourceName]; NSDebugMLLog(@"gswcomponents",@"Found %@ Language=%@ : %@",resourceName,language,path); if ([_processedDeclarationsFilePaths containsObject:path]) { NSDebugMLLog(@"gswcomponents",@"path=%@ already processed",path); path=nil; isPathAlreadyProcessed=YES; if (language) iLanguage=[_languages count]-1;//For directly go to no language search so we don't include (for exemple) an English file for a french file }; }; if (!path) { NSDebugMLLog(@"gswcomponents", @"Direct Search %@ Language=%@", completeResourceName,language); path=[resourceManager pathForResourceNamed:completeResourceName inFramework:declarationFrameworkName language:language]; if (path) { NSDebugMLLog(@"gswcomponents", @"Direct Found %@ Language=%@ : %@", completeResourceName,language,path); if ([_processedDeclarationsFilePaths containsObject:path]) { NSDebugMLLog(@"gswcomponents", @"path=%@ already processed",path); path=nil; isPathAlreadyProcessed=YES; if (language) iLanguage=[_languages count]-1;//For directly go to no language search so we don't include (for exemple) an English file for a french file }; }; NSDebugMLLog(@"gswcomponents", @"Direct Search in Component Declaration language=%@ path=%@ (_processedDeclarationsFilePaths=%@)", language, path, _processedDeclarationsFilePaths); }; NSDebugMLLog(@"gswcomponents", @"Search In Page Component: language=%@ path=%@ _processedDeclarationsFilePaths=%@", language, path, _processedDeclarationsFilePaths); }; }; if (path) { NSString* declarationsString=nil; NSDebugMLLog(@"GSWTemplateParser",@"path=%@",path); [_processedDeclarationsFilePaths addObject:path]; //NSString* pageDefPath=[path stringByAppendingString:_declarationsPath]; //TODO use encoding ! declarationsString=[NSString stringWithContentsOfFile:path]; NSDebugMLLog(@"GSWTemplateParser", @"ParseDeclarations path=%@: declarationsString:%@\n",path,declarationsString); if (declarationsString) { declarations=[self parseDeclarationsString:declarationsString named:declarationFileName inFrameworkNamed:declarationFrameworkName]; NSDebugMLLog(@"GSWTemplateParser", @"declarations:%@\n",declarations); if (!declarations) { LOGError(@"%@ Template componentDeclaration parse failed for " @"included file:%@ in framework:%@ (processedFiles=%@)", [self logPrefix], declarationFileName, declarationFrameworkName, _processedDeclarationsFilePaths); }; NSDebugMLLog(@"GSWTemplateParser",@"declarations:%@\n",declarations); } else { ExceptionRaise(@"GSWTemplateParser", @"%@ Can't load included component declaration " @"named:%@ in framework:%@ (_processedDeclarationsFilePaths=%@)", [self logPrefix], declarationFileName, declarationFrameworkName, _processedDeclarationsFilePaths); }; NSDebugMLLog(@"GSWTemplateParser",@"declarations:%@\n",declarations); } else if (isPathAlreadyProcessed) { // Returns an empty dictionary declarations=[NSDictionary dictionary]; } else { ExceptionRaise(@"GSWTemplateParser", @"%@ Can't find included component declaration " @"named:%@ in framework:%@ (processedFiles=%@)", [self logPrefix], declarationFileName, declarationFrameworkName, _processedDeclarationsFilePaths); }; NSDebugMLLog(@"GSWTemplateParser",@"Template componentDeclaration " @"includeName:%@ declarations=%@", includedFilePath, declarations); LOGObjectFnStop(); return declarations; }; //-------------------------------------------------------------------- /** parses declarations from _declarationsString if it has not been parsed **/ -(void)parseDeclarations { LOGObjectFnStart(); if (!_declarations) { NSDebugMLLog(@"GSWTemplateParser",@"_declarationsFilePath=%@", _declarationsFilePath); if ([_declarationsString length]==0) { ASSIGN(_declarations,[NSDictionary dictionary]); } else { NSDictionary* declarations=nil; DESTROY(_processedDeclarationsFilePaths); ASSIGN(_processedDeclarationsFilePaths, (_declarationsFilePath ? [NSMutableSet setWithObject:_declarationsFilePath] : [NSMutableSet set])); NSDebugMLLog(@"GSWTemplateParser", @"ParseDeclarations path=%@: declarationsString:%@\n", _declarationsFilePath,_declarationsString); declarations = [self parseDeclarationsString:_declarationsString named:_templateName inFrameworkNamed:_frameworkName]; ASSIGNCOPY(_declarations,declarations); }; }; LOGObjectFnStop(); }; //-------------------------------------------------------------------- /** parse declarationsString if it is not already done and returns declarations **/ -(NSDictionary*)declarations { LOGObjectFnStart(); if (!_declarations) [self parseDeclarations]; LOGObjectFnStop(); return _declarations; }; //-------------------------------------------------------------------- /** return declarations parsed from declarationsString **/ -(NSDictionary*)parseDeclarationsString:(NSString*)declarationsString named:(NSString*)declarationsName inFrameworkNamed:(NSString*)declarationsFrameworkName { NSDictionary* declarations=nil; GSWDeclarationParser* declarationParser=nil; NSAutoreleasePool* arpParse=nil; LOGObjectFnStart(); arpParse=[NSAutoreleasePool new]; GSWLogMemCF("New NSAutoreleasePool: %p",arpParse); declarationParser=[GSWDeclarationParser declarationParserWithPragmaDelegate:self]; NSDebugMLLog(@"GSWTemplateParser",@"name:%@ declarationsString=%@", declarationsName, declarationsString); NS_DURING { declarations=[declarationParser parseDeclarationString:declarationsString named:declarationsName inFrameworkNamed:declarationsFrameworkName]; NSDebugMLLog(@"GSWTemplateParser", @"declarations=%@", declarations); } NS_HANDLER { NSDebugMLog(@"ERROR ! %@",localException); NSDebugMLog(@"declarationsName=%@",declarationsName);//TODO NSDebugMLog(@"[self logPrefix]=%@",[self logPrefix]); LOGError(@"%@ name:%@ Declarations Parse failed!", [self logPrefix], declarationsName); localException=ExceptionByAddingUserInfoObjectFrameInfo(localException, @"%@ In [declarationsParser document]...", [self logPrefix]); [localException retain]; GSWLogMemCF("Destroy NSAutoreleasePool: %p",arpParse); DESTROY(arpParse); [localException autorelease]; [localException raise]; } NS_ENDHANDLER; NSDebugMLLog0(@"low",@"arpParse infos:\n"); [declarations retain]; NSDebugMLLog0(@"low",@"DESTROY(arpParse)\n"); GSWLogMemCF("Destroy NSAutoreleasePool: %p",arpParse); DESTROY(arpParse); NSDebugMLLog0(@"low",@"DESTROYED(arpParse)\n"); [declarations autorelease]; NSDebugMLLog(@"GSWTemplateParser", @"declarations:%@\n", declarations); LOGObjectFnStop(); return declarations; }; @end