/* parse1.cc Provides a basic parsing interface for ebstrans Copyright (C) 1993/94 C.Taegert-Kilger, Institut fuer Physiologie und Biokybernetik (IPB), Universitaet Erlangen, Deutschland Permission to use, copy, modify, distribute, and sell this software and its documentation for any purpose is hereby granted without fee, provided that the above copyright notice appear in all copies and related publications and that both that copyright notice and this permission notice appear in supporting documentation. The authors make no representations about the suitability of this software for any purpose. It is provided "as is" without express or implied warranty. Send your comments, suggestions or bug reports to ftpebs@uni-erlangen.de Or mail to Institut fuer Physiologie und Biokybernetik Markus Prosch Universitaetsstrasse 17 D-91054 Erlangen Germany $Id: parse1.cc,v 1.2 1994/12/15 10:52:35 msprosch Exp $ */ #include "parse1.h" /* Lists & their construction */ /* Construct list with next element and save arg pointer */ List::List(void* arg_, class List* next_) { arg=arg_; next=next_; is_deleted=0; }; /* Build list of two elements */ List::List(void* arg1_,void* arg2_) { arg=arg1_; next=new List(arg2_); is_deleted=0; }; List* operator +(void* el, List l) { return new List(el,&l); }; /* Destruct list */ List::~List() { if (is_deleted) ERROR(ERR_OBJECT_ALREADY_DELETED,NULL,NULL); if (GetNext()) delete(GetNext()); is_deleted=1; }; /* Get substance */ void* List::GetContent() { return(arg); }; /* Set next to value */ class List* List::SetNext( class List* next_) { next=next_; return next; }; /* Find next */ class List* List::GetNext() { return next; }; /* Searching: Get first and set search pointer */ class List* List::GetFirst() { search_pointer=GetNext(); return(this); }; class List* List::GetContinued() { List* h=search_pointer; if (search_pointer) { search_pointer=search_pointer->GetNext(); return(h); }; return(NULL); }; /* Insert element */ class List* List::InsertAfter( class List* new_element) { if (!new_element) return this; // If argument NULL: Return &yourself // and dont't modify nothing // Find last element in list to chain in class List* l; for (l=this;l->GetNext(); l=l->GetNext()) {}; l->SetNext(new_element); // Copy your own next pointer return(new_element); }; int List::GetLength() { int i=0; List* l; for (i=0,l=this;l;i++,l=l->GetNext()) {}; return(i); }; /* Basic routines */ char* remove_leading_blanks(char** input) { int res=0; char resstr[4]=""; do { res=0; sscanf(*input,"%1[ \n\t]%n",resstr,&res); res &= (strcmp("",*input)!=0); if (res) *input+=res; } while (res); return(*input); }; /* Constructor for the NOTHING parser */ Parser::Parser( void* buf_, int usage_, int consume_all_, int user_disposal_) { buf=buf_; // Get buffer user_disposal= // User provides deleting of object user_disposal_; usage=usage_; // Set usage of this object usage_o=usage_;// Store usage of this object consume_all = // Consume all flag consume_all_; is_deleted=0; }; // Constructor for the constant string parser ParserConstant::ParserConstant( const char* str_, int *buf_, int return_value_, int remove_white_, int usage_, int consume_all_, int user_disposal_): Parser(buf_,usage_,consume_all_,user_disposal_) { str=str_; remove_white=remove_white_; return_value=return_value_; }; // Parse a fixed string int ParserConstant::Parse1( char** input,void* buf) { P_TRACE("ParserConstant is called with: %s | %s | %u;", *input,str,return_value); if (remove_white) remove_leading_blanks(input); if (strncmp(str,*input,strlen(str))==0) { *input += strlen(str); if (buf) *(int *)buf=return_value; P_TRACE("... returns %s\n",*input); return(return_value); } else { P_TRACE("... returns %s\n",*input); return(0); } }; /* Constructor for simple parser */ ParserFormat::ParserFormat( void* buf_, const char* format_, int usage_, int consume_all_, int user_disposal_) : Parser(buf_,usage_,consume_all_,user_disposal_) { nread=0; // Nothing read special=NULL; // No special parameters format = format_; }; Parser::~Parser() { if (is_deleted) ERROR(ERR_OBJECT_ALREADY_DELETED,NULL,NULL); }; ParserFormat::~ParserFormat() {}; int Parser::Parse( // Input a pointer to a string which is modified char** input, // by the number of chars read, write result to buf, void* buf_) // use special parameters if necessary, modify // usage, return number of relevant bytes in buf { char *hlp = *input; // Copy pointer to input buffer char* cbuf=(char *) // Either use buffer from constructor; or buffer ( buf_ ? buf_ : buf); // from call buf = cbuf; // Copy pointer to internal buf pointer int res=0; // if (Usable()) // If this parsing object may be used at all... { res= Parse1(&hlp,cbuf);// Parse to buffer if (res) // If successfully parsed... { // ... check other things if(consume_all) // ... like: should this one be the last one? if (strcmp(remove_leading_blanks(&hlp),"")) { res=0; }; }; // end if res }; // end if usable if (res) { P_TRACE("\"%s\" -> \"%s\"\n",*input,hlp); *input=hlp; Use(); }; return (res); }; /* Basic parsing procedure which just returns true */ int Parser::Parse1( // Input a pointer to a string which is modified char**, // by the number of chars read, write result to buf, void*) // use special parameters if necessary, modify // usage, return number of relevant bytes in buf { return(1); } int ParserFormat::Parse1( // Input a pointer to a string which is modified char** input, // by the number of chars read, write result to buf, void* buf_) // use special parameters if necessary, modify // usage, return number of relevant bytes in buf { char *hlp = *input; // Copy pointer to input buffer // Catch empty string char* hlp2=hlp; if (strcmp("",remove_leading_blanks(&hlp2))==0) return 0; void* cbuf = buf_; // Copy pointer to internal buf pointer int res=0; // Number of bytes copied, ok char* format2; // New format string is to be constructed if (cbuf) { format2 = (char*) malloc(strlen(format)+strlen("%n")+1+1); strcpy(format2,format); } else { format2 = (char*) malloc(strlen(format)+strlen("%n")+2); format2[0]=format[0]; format2[1]='*'; format2[2]='\0'; strcat(format2,&format[1]); }; strcat(format2,"%n"); P_TRACE("ParserFormat \"%s\" on \"%s\"\n",format2,hlp); if (cbuf) sscanf(hlp,format2,cbuf,&res); // Read to buf else sscanf(hlp,format2,&res); // Don't read to buf *input += res; free(format2); return(res); } /* If true: Choice object may not dispose this object */ int Parser::UserDisposal() { return(user_disposal); } /* If true: This object may be used in a choice object */ int Parser::Usable() { return(usage!=0); } int Parser::Usage() { return(usage); } void Parser::SetUsage(int u) { usage=u; } int Parser::IsSatisfied() { return(usage <= 0); } /* If single use: Set to no use */ void Parser::Use() { if (Usable()) { switch(Usage()) { case 1: {}; case -1: SetUsage(0); }; } else ERROR(ERR_PARSER_SINGLE_USE,NULL,NULL); }; /* Restore original usage */ void Parser::ResetUsage() { SetUsage(usage_o); }; ParserNothing::ParserNothing( int consume_all_, int user_disposal_) : Parser(NULL,-2,consume_all_,user_disposal_) {}; int ParserNothing::Parse1( char**, void*) { return(1); }; /* Initialize tag parsing object */ ParserTag::ParserTag( const char* tag_, // Tag to find Parser* p_contents_, // Parser for contents int usage_, // Usage: Default single use int consume_all_, int user_disposal_): // Disposal; Disposed by choice object if in there ParserBag( new List(new ParserConstant(tag_,NULL,1,1,1),new List(p_contents_)), usage_,consume_all_,user_disposal_) { }; /* Initialize ParserChoice object */ ParserChoice::ParserChoice(int nobjects_,Parser** objects_, int usage_, int consume_all_, int user_disposal_) : Parser(NULL,usage_,consume_all_,user_disposal_) { nobjects=nobjects_; objects=objects_; dispose_array=0; }; /* Construct from input list */ ParserChoice::ParserChoice(List* objects_, int usage_, int consume_all_, int user_disposal_) : Parser(NULL,usage_,consume_all_,user_disposal_) { if (objects_) { int i; nobjects=objects_->GetLength(); objects=(Parser**) malloc(nobjects * sizeof(Parser*)); objects[0]=(Parser*) objects_->GetFirst()->GetContent(); for (i=1;iGetContinued()->GetContent(); }; dispose_array=1; delete(objects_); } else ERROR(ERR_INV_FUNARGS,"Invalid input list in ParserChoice.",NULL); }; void ParserChoice::ResetUsage() { for (int i=0; iResetUsage(); Parser::ResetUsage(); }; ParserChoice::~ParserChoice() { for (int i=0; iUserDisposal())) delete(objects[i]); }; if (dispose_array) free(objects); }; /* Try to parse the complete input string */ int ParserChoice::Parse1(char** input, void*) { int i,flag; do { /* Start of a turn */ P_TRACE("\"%s\" being parsed by ParserChoice\n",*input); // Remove leading blanks remove_leading_blanks(input); flag=0; for (i=0; (iUsable()) { if (objects[i]->Parse(input)) { flag=1; remove_leading_blanks(input); }; }; }; } while (flag); /* Determine success */ return(AllElementsSatisfied()); }; int ParserChoice::AllElementsSatisfied() { /* Determine successful operation */ int i=0, flag=1; for (i=0, flag=1; iIsSatisfied(),i++) {}; /*flag &= Parser::IsSatisfied();*/ return(flag); }; /* Methods for BAG */ ParserBag::ParserBag(int nobjects_,Parser** objects_, int usage_, int consume_all_, int user_disposal_) : ParserChoice(nobjects_,objects_,usage_,consume_all_,user_disposal_) {} /* Construct from input list */ ParserBag::ParserBag(List* objects_, int usage_, int consume_all_, int user_disposal_) : ParserChoice(objects_,usage_,consume_all_,user_disposal_) {} /* Try to parse the complete input string */ int ParserBag::Parse1(char** input, void*) { // Try to use up all parsing objects int i=0, flag=1; for (i=0; (iUsable() && objects[i]->Parse(input); P_TRACE("ParserBag : result %s | %i\n",*input,flag); }; /* Determine success */ return(AllElementsSatisfied()); }; /* Selective parser */ ParserSelection::ParserSelection( Parser* parser1,Parser* parser2,int usage, int consume_all_, int user_disposal_) : ParserChoice(new List(parser1,new List(parser2)), usage,consume_all_,user_disposal_) {}; ParserSelection::ParserSelection(List* parsers,int usage, int consume_all_,int user_disposal_): ParserChoice(parsers,usage,consume_all_,user_disposal_) {}; int ParserSelection::Parse1( char** input, void*) { // Try to use exactly one of the objects to parse int i=0, flag=0; for (i=0; (iUsable() && objects[i]->Parse(input); P_TRACE("%s, result %u\n",*input,flag); }; /* Determine success */ return(flag); // Exactly one element parsed! // && AllElementsSatisfied()); }; /* List parser */ ParserList::ParserList( Parser* parser_el_, Parser* parser_separator_, UseInputFn* input_fn_, int usage_, int consume_all_, int user_disposal_): Parser(NULL,usage_,consume_all_,user_disposal_) { parser_separator=parser_separator_; parser_el=parser_el_; input_fn=input_fn_; }; int ParserList::InputFn() { return 1; } int ParserList::Parse1( char** input, void* buf_) { int flag=1,flag2=1; do { flag = flag && // Try to parse main object parser_el->Parse(input,buf_); parser_el->ResetUsage(); if (flag) // If success: Apply input fn { if (input_fn) flag = flag && InputFn() && input_fn(); else flag = flag && InputFn(); } if (flag) { if(parser_separator) // If separator given: { flag2 = parser_separator-> // Try to parse it Parse(input,buf_); if (flag2) parser_separator->ResetUsage(); } else flag2=1; } else flag2=0; } while (flag2); return(flag); }; ParserList::~ParserList() { if (parser_el && !(parser_el->UserDisposal())) delete(parser_el); if (parser_separator && !(parser_separator->UserDisposal())) delete(parser_separator); }; /* Create a single string from command line parameters */ char* CreateArgString(int argc, char **argv) { int i,arglen; // Temporary storage char* args; // Calculate complete lenght of args for (i=1,arglen=0; i