/****************************************************************************************************/
/* */
/* generate.main.c: */
/* */
/****************************************************************************************************/
/****************************************************************************************************/
/* */
/* Copyright (C) 2003, 2004 Joerg Kunze */
/* */
/* This file is part of siliconBrain. */
/* */
/* siliconBrain is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 2 of the License, or */
/* (at your option) any later version. */
/* */
/* siliconBrain 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 General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program; if not, write to the Free Software */
/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/* */
/****************************************************************************************************/
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include <errno.h>
#include <pwd.h>
#include <obstack.h>
#define obstack_chunk_alloc malloc
#define obstack_chunk_free free
#include "glib.h"
#include "siliconBrainLib"
#include "siliconBrainSpecification"
static const char *siliconBrainRelease = "$siliconBrainRelease: 0.2.3 $";
static const char *siliconBrainRcsIdentifier = "$Id: generate.main.c,v 1.27 2004/12/14 23:31:26 joerg Exp $";
static const char *siliconBrainSaveStamp = "$siliconBrainSaveStamp: 2004/12/14 22:29:54, Joerg Kunze$";
/****************************************************************************************************/
/* */
/* List: */
/* */
/****************************************************************************************************/
typedef struct ListElem {
struct ListElem *next;
char data;
} ListElem;
typedef struct List {
ListElem anchor;
ListElem *last;
size_t dataSize;
struct obstack obstack;
} List;
void listOpen( List *list, size_t dataSize ) {
list->anchor.next = 0;
list->last = &list->anchor;
list->dataSize = dataSize + sizeof( ListElem * );
obstack_init( &list->obstack );
}
void *listAppend( List *list ) {
list->last = list->last->next = obstack_alloc( &list->obstack, list->dataSize );
list->last->next = 0;
return &(list->last->data);
}
void listClose( List * list ) {
obstack_free( &list->obstack, 0 );
}
#define listFor( list, iterator, dataPointer ) \
for( (iterator) = (list)->anchor.next; (iterator)&& ((dataPointer) = (void *)(&(iterator)->data)); (iterator) = (iterator)->next )
void listTest() {
struct {
int a;
int b;
} *foo;
List list;
listOpen( &list, sizeof *foo );
foo = listAppend( &list );
foo->b = 42;
foo = listAppend( &list );
foo->b = 23;
foo = listAppend( &list );
foo->b = 666;
ListElem *iterator;
listFor( &list, iterator, foo ) printf( "foo is %d\n", foo->b );
listClose( &list );
}
/****************************************************************************************************/
/* */
/* command: */
/* */
/****************************************************************************************************/
typedef enum {
isCommand = 1,
isRecord
} StructureType;
typedef enum {
isOption = 1,
isField
} ElementType;
typedef struct {
char *name;
char *shortDescription;
char *longDescription;
char oneCharacterName;
char *typeName;
OptionType type;
ElementType elementType;
} Option;
typedef struct {
Specification specification;
List options;
StructureType structureType;
bool withoutStandardOptions;
bool isFileCommand;
} LocalCommand;
typedef struct {
char *comment;
char *versionFormat;
void (*formatStartMain)( const LocalCommand *);
void (*formatTitle )( const LocalCommand *);
void (*formatOption )( const Option *, int optionIndex );
void (*formatEndMain )( const LocalCommand *);
} Formater;
#define forEachOption( body ) \
{ \
int optionIndex = 0; \
Option *option; \
ListElem *iterator; \
listFor( &command->options, iterator, option ) { \
body; \
++optionIndex; \
} \
}
/****************************************************************************************************/
/* */
/* LocalXmlUserData: */
/* */
/****************************************************************************************************/
typedef enum {
localContextNo,
localContextInCommand,
localContextInCommandInShortDescription,
localContextInCommandInLongDescription,
localContextInOption,
localContextInOptionInShortDescription,
localContextInOptionInLongDescription,
localContextInFile,
localContextInFileCommandOpen,
localContextInFileCommandClose,
localContextInFileFileOpen,
localContextInFileFileClose,
} LocalXmlContextState;
typedef struct LocalXmlUserData {
LocalCommand *command;
Option *option;
LocalXmlContextState state;
bool first;
} LocalXmlUserData;
/****************************************************************************************************/
/* */
/* prototype: */
/* */
/****************************************************************************************************/
static void generateAll( const Formater *formater, const LocalCommand *command );
/****************************************************************************************************/
/* */
/* parser: */
/* */
/****************************************************************************************************/
/****************************************************************************************************/
/* */
/* xmlStart: */
/* */
/****************************************************************************************************/
static void xmlStartElement(
GMarkupParseContext *context,
const gchar *name,
const gchar **attribute,
const gchar **value,
gpointer userData,
GError **error
) {
LocalXmlUserData *user = userData;
struct obstack *obstack = &user->command->options.obstack;
ElementType elementType;
switch( user->state ) {
case localContextNo:
if(
( !strcmp( name, "command" ) && (user->command->structureType = isCommand) ) ||
( !strcmp( name, "record" ) && (user->command->structureType = isRecord ) )
) {
user->state = localContextInCommand;
Specification *specification = &user->command->specification;
if( user->first ) {
while( *attribute ) {
char *allocatedValue = obstack_copy0( obstack, *value, strlen( *value ) );
if( !strcmp( *attribute, "name" ) ) {
specification->name = allocatedValue;
}
else if( !strcmp( *attribute, "release" ) ) {
specification->release = allocatedValue;
}
else if( !strcmp( *attribute, "rcsIdentifier" ) ) {
specification->rcsIdentifier = allocatedValue;
}
else if( !strcmp( *attribute, "saveStamp" ) ) {
specification->saveStamp = allocatedValue;
}
else if( !strcmp( *attribute, "title" ) ) {
specification->title = allocatedValue;
}
*attribute++;
*value++;
}
}
}
break;
case localContextInCommand:
if( !strcmp( name, "shortDescription" ) ) {
user->state = localContextInCommandInShortDescription;
}
else if( !strcmp( name, "longDescription" ) ) {
user->state = localContextInCommandInLongDescription;
}
else if( !strcmp( name, "withoutStandardOptions" ) ) {
user->command->withoutStandardOptions = true;
}
else if( !strcmp( name, "file" ) ) {
user->command->isFileCommand = true;
user->state = localContextInFile;
}
else if(
(!strcmp( name, "option" ) && (elementType = isOption) ) ||
(!strcmp( name, "field" ) && (elementType = isField ) )
) {
user->state = localContextInOption;
user->option = listAppend( &user->command->options );
user->option->elementType = elementType;
while( *attribute ) {
char *allocatedValue = obstack_copy0( obstack, *value, strlen( *value ) );
if( !strcmp( *attribute, "name" ) ) {
user->option->name = allocatedValue;
}
else if( !strcmp( *attribute, "oneCharacterName" ) ) {
user->option->oneCharacterName = allocatedValue[ 0 ];
}
else if( !strcmp( *attribute, "type" ) ) {
user->option->type = !strcmp( allocatedValue, "value" ) ? optionValue : optionFlag;
}
else if( !strcmp( *attribute, "typeName" ) ) {
user->option->typeName = allocatedValue;
}
*attribute++;
*value++;
}
}
break;
case localContextInCommandInShortDescription:
break;
case localContextInCommandInLongDescription:
break;
case localContextInOption:
if( !strcmp( name, "shortDescription" ) ) {
user->state = localContextInOptionInShortDescription;
}
else if( !strcmp( name, "longDescription" ) ) {
user->state = localContextInOptionInLongDescription;
}
break;
case localContextInOptionInShortDescription:
break;
case localContextInOptionInLongDescription:
break;
case localContextInFile:
if( strequ( name, "openCommand" ) ) {
user->state = localContextInFileCommandOpen;
}
else if( strequ( name, "closeCommand" ) ) {
user->state = localContextInFileCommandClose;
}
else if( strequ( name, "openFile" ) ) {
user->state = localContextInFileFileOpen;
}
else if( strequ( name, "closeFile" ) ) {
user->state = localContextInFileFileClose;
}
break;
case localContextInFileCommandOpen:
break;
case localContextInFileCommandClose:
break;
case localContextInFileFileOpen:
break;
case localContextInFileFileClose:
break;
}
}
/****************************************************************************************************/
/* */
/* xmlEnd: */
/* */
/****************************************************************************************************/
static void xmlEndElement(
GMarkupParseContext *context,
const gchar *element_name,
gpointer user_data,
GError **error
) {
LocalXmlUserData *user = user_data;
/*----------------------------------------------------------*/
/* tags with no inner context: don't go up in context stack */
/*----------------------------------------------------------*/
if( strequ( element_name, "withoutStandardOptions" ) ) return;
switch( user->state ) {
case localContextNo:
user->state = localContextNo;
break;
case localContextInCommand:
user->state = localContextNo;
break;
case localContextInCommandInShortDescription:
user->state = localContextInCommand;
break;
case localContextInCommandInLongDescription:
user->state = localContextInCommand;
break;
case localContextInOption:
user->state = localContextInCommand;
break;
case localContextInOptionInShortDescription:
user->state = localContextInOption;
break;
case localContextInOptionInLongDescription:
user->state = localContextInOption;
break;
case localContextInFile:
user->state = localContextInCommand;
break;
case localContextInFileCommandOpen:
user->state = localContextInFile;
break;
case localContextInFileCommandClose:
user->state = localContextInFile;
break;
case localContextInFileFileOpen:
user->state = localContextInFile;
break;
case localContextInFileFileClose:
user->state = localContextInFile;
break;
}
}
/****************************************************************************************************/
/* */
/* xmlText: */
/* */
/****************************************************************************************************/
static void xmlText(
GMarkupParseContext *context,
const gchar *text,
gsize textLength,
gpointer user_data,
GError **error
) {
LocalXmlUserData *user = user_data;
/*---------------------------------*/
/* ignore text in ceratin contexts */
/*---------------------------------*/
switch( user->state ) {
case localContextNo:
case localContextInCommand:
return;
default: break;
}
Specification *specification = &user->command->specification;
struct obstack *obstack = &user->command->options.obstack;
const char *textEnd = text + textLength - 1;
Option *option = user->option;
/*--------------------------------------------*/
/* trim text: skip left and right white space */
/*--------------------------------------------*/
while( textLength ) {
switch( *text ) {
case ' ': case '\n': case '\t':
--textLength;
++text;
break;
default:
goto endOfPrefix;
}
}
endOfPrefix:
while( textLength ) {
switch( *textEnd ) {
case ' ': case '\n': case '\t': case 0:
--textLength;
--textEnd;
break;
default:
goto endOfSuffix;
}
}
endOfSuffix:
/*-----------------------------*/
/* context dependend copy text */
/*-----------------------------*/
switch( user->state ) {
case localContextInCommandInShortDescription:
if( !user->first ) break;
specification->shortDescription = obstack_copy0( obstack, text, textLength );
break;
case localContextInCommandInLongDescription:
if( !user->first ) break;
specification->longDescription = obstack_copy0( obstack, text, textLength );
break;
case localContextInFileCommandOpen:
if( !user->first ) break;
specification->commandOpen = obstack_copy0( obstack, text, textLength );
break;
case localContextInFileCommandClose:
if( !user->first ) break;
specification->commandClose = obstack_copy0( obstack, text, textLength );
break;
case localContextInFileFileOpen:
if( !user->first ) break;
specification->fileOpen = obstack_copy0( obstack, text, textLength );
break;
case localContextInFileFileClose:
if( !user->first ) break;
specification->fileClose = obstack_copy0( obstack, text, textLength );
break;
case localContextInOption:
break;
case localContextInOptionInShortDescription:
option->shortDescription = obstack_copy0( obstack, text, textLength );
break;
case localContextInOptionInLongDescription:
option->longDescription = obstack_copy0( obstack, text, textLength );
break;
default: break;
}
}
static GMarkupParser parser = { &xmlStartElement, &xmlEndElement, &xmlText, 0, 0 };
/****************************************************************************************************/
/* */
/* formatH: */
/* */
/****************************************************************************************************/
static void formatStartMainH( const LocalCommand *command ) {
puts( "/* generated H-file. -*-c-*- */\n" );
}
static void formatTitleH( const LocalCommand *command ) {
puts(
"\n#include <stdbool.h>\n"
"\n#include \"siliconBrainLib\"\n"
"\n#include \"siliconBrainOption\"\n"
);
puts( "typedef struct {" );
}
static void formatOptionH( const Option *option, int optionIndex ) {
printf(
" %s %s; /* %s */\n",
option->type == optionFlag ? "bool " : "char *",
option->name,
option->shortDescription
);
}
static void formatEndMainH( const LocalCommand *command ) {
char *typeName, *variableName;
if( command->structureType == isCommand ) {
typeName = "Options";
variableName = "options";
} else {
typeName = "Fields";
variableName = "fields";
}
printf( "} %s%s;\n\n", command->specification.name, typeName );
printf( "CommandReturnCode %s( const %s%s *%s", command->specification.name, command->specification.name, typeName, variableName );
if( command->isFileCommand )
printu( ", void *commandData, String source" );
printu( " );\n" );
if( command->specification.commandOpen ) printf( "void *%s( const %s%s *options );\n" , command->specification.commandOpen , command->specification.name, typeName );
if( command->specification.commandClose ) printf( "CommandReturnCode %s( const %s%s *options, void * );\n" , command->specification.commandClose, command->specification.name, typeName );
if( command->specification.fileOpen ) printf( "CommandReturnCode %s( const %s%s *options, void *, String );\n", command->specification.fileOpen , command->specification.name, typeName );
if( command->specification.fileClose ) printf( "CommandReturnCode %s( const %s%s *options, void *, String );\n", command->specification.fileClose , command->specification.name, typeName );
puts( "/* END */" );
}
static const Formater formatH = {
.comment = "//",
.formatStartMain = &formatStartMainH,
.formatTitle = &formatTitleH ,
.formatOption = &formatOptionH ,
.formatEndMain = &formatEndMainH
};
/****************************************************************************************************/
/* */
/* formatC: */
/* */
/****************************************************************************************************/
static void formatStartMainC( const LocalCommand *command ) {
puts(
"#include <stdio.h>\n"
"#include <getopt.h>\n"
"#include <stdlib.h>\n\n"
"#include \"siliconBrainOption\"\n"
);
if( command->structureType == isCommand ) {
printf( "#include \"%s\"\n\n", command->specification.name );
printf( "extern const char *%sSiliconBrainRelease;\n" , command->specification.name );
printf( "extern const char *%sSiliconBrainRcsIdentifier;\n", command->specification.name );
printf( "extern const char *%sSiliconBrainSaveStamp;\n\n" , command->specification.name );
} else {
puts( "#include \"record\"" );
printf( "#include \"%s.record\"\n\n", command->specification.name );
}
puts( "int main( int argc, char *argv[] ) {" );
}
static void formatTitleC( const LocalCommand *command ) {
if( command->structureType == isOption ) {
puts(
" Obstack obstack;\n"
" obstack_init( &obstack );\n"
);
printf( " %sOptions options = {0};\n", command->specification.name );
} else {
printf( " %sFields fields = {0};\n", command->specification.name );
fflush( stdout );
system ( "record.specification | generate --optionMeat" );
return;
}
/*---------------------------------------*/
/* build options short descriptor string */
/*---------------------------------------*/
fputs( " static const char optionsShortDescriptor[] = \"", stdout );
forEachOption(
if( option->oneCharacterName ) {
putchar( option->oneCharacterName );
if( option->type != optionFlag ) putchar( ':' );
}
);
puts( "\";" );
/*--------------------------------------*/
/* build options long descriptor string */
/*--------------------------------------*/
puts( " static const struct option optionsLongDescriptor[] = {" );
int numberOfOptions = 0;
forEachOption(
printf(
" {\n"
" .name = \"%s\",\n"
" .has_arg = optional_argument\n"
" },\n",
option->name
);
++numberOfOptions;
);
forEachOption(
if( option->type == optionFlag ) {
printf(
" {\n"
" .name = \"no-%s\",\n"
" .has_arg = no_argument\n"
" },\n",
option->name
);
}
);
puts(
" { 0 }\n"
" };\n"
);
/*----------------------------------------*/
/* build options siliconBrains descriptor */
/*----------------------------------------*/
puts( " OptionProcessed optionProcessed[] = {" );
forEachOption(
printf(
" {\n"
" .name = optionsLongDescriptor[ %d ].name,\n"
" .alreadyConfigured = false,\n"
" .value = &options.%s,\n"
" .optionType = %s\n"
" },\n",
optionIndex,
option->name,
option->type == optionFlag ? "optionFlag" : "optionValue"
);
);
puts(
" { 0 }\n"
" };\n"
);
puts(
" int optionIndex = 0;\n"
" int optionCharacter;\n\n"
" while( 1 ) {\n"
" optionCharacter = getopt_long( argc, argv, optionsShortDescriptor, optionsLongDescriptor, &optionIndex );\n\n"
" if( optionCharacter == -1 ) break;\n\n"
" switch( optionCharacter ) {\n"
" case 0: break;\n"
);
forEachOption(
if( option->oneCharacterName )
printf(
" case '%c': optionIndex = %d; break;\n",
option->oneCharacterName,
optionIndex
);
);
puts(
" case '?': exit( 42 );\n"
" default: exit( 43 );\n"
" };\n"
);
puts( " if( !optarg ) optarg = \"\";\n" );
puts( " bool flagNegation;\n" );
printf( " int numberOfOptions = %d;\n", numberOfOptions );
puts(
" if( optionIndex >= numberOfOptions ) {\n"
" switch( optionIndex - numberOfOptions ) {\n"
);
int flagOptionIndex = 0;
forEachOption(
if( option->type == optionFlag ) {
printf(
" case %d: optionIndex = %d; break;\n",
flagOptionIndex, optionIndex
);
++flagOptionIndex;
}
);
puts(
" }\n"
" flagNegation = true;\n"
" } else {\n"
" flagNegation = false;\n"
" }\n"
);
puts( " optionProcessed[ optionIndex ].alreadyConfigured = true;" );
puts( " switch( optionIndex ) {\n" );
forEachOption(
printf( " case %d:\n", optionIndex );
if( option->type == optionFlag ) {
printf( " options.%s = stringToBool( optarg );\n", option->name );
printf(
" if( flagNegation )\n"
" options.%s = !options.%s;\n"
,option->name, option->name
);
} else {
printf( " options.%s = optarg;\n", option->name );
}
puts( " break;\n" );
);
puts(
" default: exit( 44 );\n"
" }\n"
" }\n"
);
puts(
"\n"
" if( !options.complete ) {\n"
);
const char * const package = getenv( "siliconBrainPackageName" );
forEachOption(
printf( " if( !optionProcessed[ %d ].alreadyConfigured && (optarg = getenv( \"%s_%s\" )) ) {\n", optionIndex, package, option->name );
if( option->type == optionFlag ) {
printf( " options.%s = stringToBool( optarg );\n", option->name );
} else {
printf( " options.%s = optarg;\n", option->name );
}
printf( " optionProcessed[ %d ].alreadyConfigured = true;\n", optionIndex );
puts( " }\n" );
);
puts(
" }\n"
);
printf( "if( !options.complete ) optionReadOptions( optionProcessed, &obstack, \"%s\" );\n\n", package );
}
static void formatOptionC( const Option *option, int optionIndex ) {
}
static void formatEndMainC( const LocalCommand *command ) {
/*----------------------------------------*/
/* generate handling of the `help' option */
/*----------------------------------------*/
puts( " if( options.help ) {" );
printf( " puts( \"%s\" );\n", command->specification.title );
int optionNameLength = 0;
int optionNameLengthCandidate = 0;
forEachOption(
optionNameLengthCandidate = strlen( option->name );
optionNameLength >= optionNameLengthCandidate || (optionNameLength = optionNameLengthCandidate);
);
if( command->structureType == isCommand ) {
puts( " puts(\n \"Invoke it like:\\n\"" );
forEachOption(
printf( " \" --%-*.*s %c%c (%s) %s\\n\"\n",
optionNameLength,
optionNameLength,
option->name,
option->oneCharacterName ? '-' : ' ',
option->oneCharacterName ? option->oneCharacterName : ' ',
option->type == optionFlag ? "flag " : "value",
option->shortDescription
);
);
} else {
puts( " puts(\n \"The fields:\\n\"" );
forEachOption(
printf( " \" %-*.*s (%s) %s\\n\"\n",
optionNameLength,
optionNameLength,
option->name,
option->typeName,
option->shortDescription
);
);
{
FILE *recordHelp = popen( "record --help", "r" );
int recordLength = 200;
char *recordLine = malloc( recordLength );
char *lineIterator;
while( -1 != getline( &recordLine, &recordLength, recordHelp ) ) {
printu( " \"" );
for( lineIterator = recordLine; *lineIterator; ++lineIterator ) {
switch( *lineIterator ) {
case '\n': printu( "\\n" ); break;
case '\t': printu( "\\t" ); break;
case '\\': printu( "\\\\" ); break;
case '"' : printu( "\\\"" ); break;
default : putchar( *lineIterator );
}
}
printu( "\"\n" );
}
free( recordLine );
}
}
puts(
" );\n"
" exit( 0 );\n"
" }"
);
/*-------------------------------------------*/
/* generate handling of the `version' option */
/*-------------------------------------------*/
puts(
" if( options.version ) {\n"
" puts( versionString );"
);
if( command->structureType == isCommand ) {
printf(
" puts( \"// Implementation:\" );\n"
" printf(\n"
" \"// %%s\\n\"\n"
" \"// %%s\\n\"\n"
" \"// %%s\\n\",\n"
" %sSiliconBrainRelease,\n"
" %sSiliconBrainRcsIdentifier,\n"
" %sSiliconBrainSaveStamp\n"
" );",
command->specification.name,
command->specification.name,
command->specification.name
);
}
puts(
" exit( 0 );\n"
" }"
);
/*-------------------------------------------*/
/* call the command implementinging function */
/*-------------------------------------------*/
puts( " CommandReturnCode returnCode = commandOk;\n" );
if( command->isFileCommand ) {
printu( " {\n"
" FileReaderContext context;\n" );
printf( " context.openCommand = (void *)%s;\n", command->specification.commandOpen ?: "0" );
printf( " context.closeCommand = (void *)%s;\n", command->specification.commandClose ?: "0" );
printf( " context.openFile = (void *)%s;\n", command->specification.fileOpen ?: "0" );
printf( " context.closeFile = (void *)%s;\n", command->specification.fileClose ?: "0" );
printf( " context.userCommand = (UserCommand)&%s;\n", command->specification.name );
printu( " returnCode = fileReader( &context, &options, argc-optind, argv + optind );\n"
" }\n" );
}
else if( command->structureType == isOption )
printf( " returnCode = %s( &options );\n", command->specification.name );
else
printf( " returnCode = %s( &fields );\n" , command->specification.name );
puts( " return returnCode;\n}" );
}
static const Formater formatC = {
.comment = "//",
.formatStartMain = &formatStartMainC,
.formatTitle = &formatTitleC ,
.formatOption = &formatOptionC ,
.formatEndMain = &formatEndMainC ,
.versionFormat =
"static const char versionString[] =\n"
" \"%s %s\\n\"\n"
" \"\\n\"\n"
" \"%s generated at: %s\\n\"\n"
" \"%s in directory: %s\\n\"\n"
" \"%s on host : %s\\n\"\n"
" \"%s by user : %s, %s\\n\"\n"
" \"\\n\"\n"
" \"%s generated for specification:\\n\"\n"
" \"%s %s\\n\"\n"
" \"%s %s\\n\"\n"
" \"%s %s\\n\"\n"
" \"\\n\"\n"
" \"%s generated with generator:\\n\"\n"
" \"%s %s\\n\"\n"
" \"%s %s\\n\"\n"
" \"%s %s\\n\";\n"
};
/****************************************************************************************************/
/* */
/* formatConfigurationReader: */
/* */
/****************************************************************************************************/
static void formatStartMainConfigurationReader( const LocalCommand *command ) {
puts(
"#include <stdio.h>\n"
"#include <getopt.h>\n"
"#include <stdlib.h>\n"
"#include <obstack.h>\n"
"\n"
"#define obstack_chunk_alloc malloc\n"
"#define obstack_chunk_free free\n"
"\n"
"#define siliconBrainPrintShortNames\n"
"#include \"siliconBrainLib\"\n"
"#include \"siliconBrainOption\""
);
generateAll( &formatH, command );
printf( "extern const char *%sSiliconBrainRelease;\n" , command->specification.name );
printf( "extern const char *%sSiliconBrainRcsIdentifier;\n", command->specification.name );
printf( "extern const char *%sSiliconBrainSaveStamp;\n\n" , command->specification.name );
puts(
"int main( int argc, char *argv[] ) {\n"
"\n"
" SiliconBrainPrinter siliconBrainPrinter;\n"
);
}
static void formatTitleConfigurationReader( const LocalCommand *command ) {
formatTitleC( command );
int completeOptionIndex = -1;
forEachOption(
if( strequ( option->name, "complete" ) ) {
completeOptionIndex = optionIndex;
goto completeOptionIndexFound;
}
);
completeOptionIndexFound:
printf(
" options.complete = true;\n"
" optionProcessed[ %d ].alreadyConfigured = true;\n\n", completeOptionIndex
);
puts(
" while( *argv && !strequ( *argv, \"--\" ) ) {\n"
" --argc;\n"
" ++argv;\n"
" }\n"
"\n"
" siliconBrainPrinterInit( &siliconBrainPrinter, argc, (const char **)argv );\n"
);
printf( " comment( \"%s\\n%s\" );\n", command->specification.title, command->specification.shortDescription );
printf( " tag( \"%s\" );\n", getenv( "siliconBrainPackageName" ) );
}
static void formatOptionConfigurationReader( const Option *option, int optionIndex ) {
printf( " comment( \"%s (%s) : %s\" );\n",
option->name,
option->type == optionFlag ? "flag " : "value",
option->shortDescription
);
printf( " if( optionProcessed[ %d ].alreadyConfigured ) {\n", optionIndex );
if( option->type == optionFlag ) {
printf( " keyBool( \"%s\",\n", option->name );
} else {
printf( " key( \"%s\",\n", option->name );
}
printf( " options.%s\n", option->name );
puts(
" );\n"
" }\n"
);
}
static void formatEndMainConfigurationReader( const LocalCommand *command ) {
puts(
" end();\n"
"\n"
" return 0;\n}"
);
}
static const Formater formatConfigurationReader = {
.comment = "//",
.formatStartMain = &formatStartMainConfigurationReader,
.formatTitle = &formatTitleConfigurationReader ,
.formatOption = &formatOptionConfigurationReader ,
.formatEndMain = &formatEndMainConfigurationReader ,
};
/****************************************************************************************************/
/* */
/* formatCommand: */
/* */
/****************************************************************************************************/
static void formatStartMainCommand( const LocalCommand *command ) {
puts( "/* generated Command-file. -*-c-*- */\n" );
}
static void formatTitleCommand( const LocalCommand *command ) {
puts( "\n\n#include <stdbool.h>" );
puts( "#include <stdio.h>\n" );
printf( "#include \"%s.record\"\n\n", command->specification.name );
printf( "int %s( const %sFields *fields ) {\n", command->specification.name, command->specification.name );
puts( " puts( \"High Du!\" );" );
puts( " return 0;" );
puts( "}" );
}
static void formatOptionCommand( const Option *option, int optionIndex ) {
}
static void formatEndMainCommand( const LocalCommand *command ) {
}
static const Formater formatCommand = {
.comment = "//",
.formatStartMain = &formatStartMainCommand,
.formatTitle = &formatTitleCommand ,
.formatOption = &formatOptionCommand ,
.formatEndMain = &formatEndMainCommand
};
/****************************************************************************************************/
/* */
/* formatPlain: */
/* */
/****************************************************************************************************/
static void formatStartMainPlain( const LocalCommand *command ) {
puts( "This is the specification for a command" );
}
static void formatTitlePlain( const LocalCommand *command ) {
printf( "Title: \"%s\"\n", command->specification.title );
printf( "short: \"%s\"\n", command->specification.shortDescription );
printf( "long : \"%s\"\n", command->specification.longDescription );
}
static void formatOptionPlain( const Option *option, int optionIndex ) {
printf( "\nOption:\n Name: %s\n", option->name );
printf(
" --%s %c%c (%s)\n"
"%s\n%s\n\n",
option->name,
option->oneCharacterName ? '-' : ' ',
option->oneCharacterName ? option->oneCharacterName : ' ',
option->type == optionFlag ? "flag " : "value",
option->shortDescription,
option->longDescription ? : ""
);
}
static void formatEndMainPlain( const LocalCommand *command ) {
puts( "End" );
}
static const Formater formatPlain = {
.comment = "",
.formatStartMain = &formatStartMainPlain,
.formatTitle = &formatTitlePlain ,
.formatOption = &formatOptionPlain ,
.formatEndMain = &formatEndMainPlain
};
/****************************************************************************************************/
/* */
/* formatTexinfo: */
/* */
/****************************************************************************************************/
static void formatStartMainTexinfo( const LocalCommand *command ) {
char* recordSuffix = (command->structureType == isRecord ? ".record" : "");
printf( "@node %s%s\n" , command->specification.name, recordSuffix );
printf( "@section %s%s\n", command->specification.name, recordSuffix );
printf( "%s\n" , command->specification.title );
}
static void formatTitleTexinfo( const LocalCommand *command ) {
puts( "@subsection Description" );
printf( "%s\n\n", command->specification.shortDescription );
printf( "%s\n\n", command->specification.longDescription );
printf(
"@subsection %s\n"
"@table @samp\n\n",
command->structureType == isRecord ? "Fields" : "Options"
);
}
static void formatOptionTexinfo( const Option *option, int optionIndex ) {
if( option->elementType == isOption ) {
printf(
"@item --%s %c%c (%s)\n"
"%s\n%s\n\n",
option->name,
option->oneCharacterName ? '-' : ' ',
option->oneCharacterName ? option->oneCharacterName : ' ',
option->type == optionFlag ? "flag " : "value",
option->shortDescription,
option->longDescription ? : ""
);
} else {
printf(
"@item %s (%s)\n"
"%s\n%s\n\n",
option->name,
option->typeName,
option->shortDescription,
option->longDescription ? : ""
);
}
}
static void formatEndMainTexinfo( const LocalCommand *command ) {
puts( "@end table" );
}
static const Formater formatTexinfo = {
.comment = "@c",
.formatStartMain = &formatStartMainTexinfo,
.formatTitle = &formatTitleTexinfo ,
.formatOption = &formatOptionTexinfo ,
.formatEndMain = &formatEndMainTexinfo
};
/****************************************************************************************************/
/* */
/* generateAll: produce all output. */
/* */
/****************************************************************************************************/
static void generateAll( const Formater *formater, const LocalCommand *command ) {
Specification generatorSpecification = {
.release = siliconBrainRelease,
.rcsIdentifier = siliconBrainRcsIdentifier,
.saveStamp = siliconBrainSaveStamp
};
(*formater->formatStartMain)( command );
formatHeader( formater->comment, &command->specification, &generatorSpecification, formater->versionFormat );
(*formater->formatTitle )( command );
forEachOption(
(*formater->formatOption)( option, optionIndex );
)
(*formater->formatEndMain )( command );
}
/****************************************************************************************************/
/* */
/* addStandardOptions: */
/* */
/****************************************************************************************************/
static void addStandardOptions( LocalCommand *command ) {
static const Option standardOptions[] = {
{
.name = "help",
.shortDescription = "Print a short help message, listing the options.",
.longDescription =
"Just a short listing of all available options. In case of records "
"(AKA record commands) before the options a list of its fields "
"is printed. For deeper and more information use man or better "
"info.",
.oneCharacterName = 'h',
.elementType = isOption,
.type = optionFlag
},
{
.name = "verbose",
.shortDescription = "Let this command talk to you a lot.",
.longDescription =
"When this option is set, the command produces a lot of output. "
"This output is written to stderr. This makes it possible to use the "
"verbose mode even, if the actual data is transported via stdout. Without "
"this options the comannd is more or less quiet, except when errors ocurre.",
.oneCharacterName = 'v',
.elementType = isOption,
.type = optionFlag
},
{
.name = "version",
.shortDescription = "Display version information.",
.longDescription =
"The version information available for command is printed. This is the "
"release number, the RCS identifier and the date of last save the source. This three "
"values are given for the command specification and for the command implementation.",
.elementType = isOption,
.type = optionFlag
},
{
.name = "output",
.shortDescription = "File to which output is written.",
.longDescription =
"Says to which file the output should be written. "
"In future it will be extended by a complex data direction "
"system.",
.oneCharacterName = 'o',
.elementType = isOption,
.type = optionValue
},
{
.name = "complete",
.shortDescription = "Indicate completeness of specified options. No further lookup in configuration chain.",
.longDescription =
"The configuration chain is a number of locations, in which the options processing is looking for specifications of command "
"and package options (all package options are command options as well). These locations are looked up in a predefined sequence. "
"This is the configuration chain. An option is taken from the first location where it is found. The first location to look is the "
"command line options followed by the environment variables then a configuration placed in the current directory, home directory, /etc. "
"For performance reasons or other, the --complete option stops further lookup in the configuation chain. For example using --complete "
"in the command line will avoid reading the environment. The configurationReader will always set this option, because it has read the "
"complete chain already.",
.elementType = isOption,
.type = optionFlag
},
};
const Option *begin = &standardOptions[ 0 ];
const Option *end = &standardOptions[ sizeof( standardOptions ) / sizeof( Option ) ];
const Option *source;
Option *target;
for( source = begin; source != end; ++source ) {
target = listAppend( &command->options );
memcpy( target, source, sizeof( *target ) );
}
}
/****************************************************************************************************/
/* */
/* main: */
/* */
/****************************************************************************************************/
extern int main( int argc, char *argv[] ) {
bool optionMeat = (argv[ 1 ] && !strcmp( argv[ 1 ], "--optionMeat" ));
char xmlStreamChunk[ 1234 ];
size_t xmlStreamChunkLength;
GError *error;
LocalCommand command = {
.specification = {
.name = 0,
.title = 0,
.shortDescription = 0,
.longDescription = 0,
.release = 0,
.rcsIdentifier = 0,
.saveStamp = 0,
.commandOpen = 0,
.commandClose = 0,
.fileOpen = 0,
.fileClose = 0,
},
.withoutStandardOptions = false,
.isFileCommand = false
};
LocalXmlUserData xmlUserData = {
.command = &command,
.option = 0,
.state = localContextNo,
.first = true
};
GMarkupParseContext *context = g_markup_parse_context_new( &parser, 0, &xmlUserData, 0 );
listOpen( &command.options, sizeof( Option ) );
while( xmlStreamChunkLength = fread( xmlStreamChunk, 1, sizeof( xmlStreamChunk ) - 1, stdin ) )
g_markup_parse_context_parse( context, xmlStreamChunk, xmlStreamChunkLength, &error);
xmlUserData.first = false;
if(
command.structureType == isCommand &&
!command.withoutStandardOptions &&
!strequ( argv[ 1 ], "--configurationReader" )
) {
FILE *packageSpecificationFile = 0;
char *specificationName;
asprintf( &specificationName, "temporary/%s.specification", getenv( "siliconBrainPackageName" ) );
packageSpecificationFile = popen( specificationName, "r" );
if( packageSpecificationFile ) {
while( xmlStreamChunkLength = fread( xmlStreamChunk, 1, sizeof( xmlStreamChunk ) - 1, packageSpecificationFile ) )
g_markup_parse_context_parse( context, xmlStreamChunk, xmlStreamChunkLength, &error);
pclose( packageSpecificationFile );
}
free( specificationName );
}
g_markup_parse_context_end_parse( context, &error );
g_markup_parse_context_free ( context );
if( command.structureType == isCommand )
addStandardOptions( &command );
/*---------------------------------------------------------------------------*/
/* Hack, t reuse the option handling of the record.command for other records */
/*---------------------------------------------------------------------------*/
if( optionMeat ) {
formatTitleC( &command );
}
else {
/*----------------------------------*/
/* standard generator of everything */
/*----------------------------------*/
generateAll(
argv[ 1 ] ?
!strcmp( argv[ 1 ], "--c" ) ? &formatC :
!strcmp( argv[ 1 ], "--h" ) ? &formatH :
!strcmp( argv[ 1 ], "--texinfo" ) ? &formatTexinfo :
!strcmp( argv[ 1 ], "--command" ) ? &formatCommand :
!strcmp( argv[ 1 ], "--configurationReader" ) ? &formatConfigurationReader :
&formatPlain
: &formatPlain,
&command
);
}
listClose( &command.options );
return 0;
}
/*
$Log: generate.main.c,v $
Revision 1.27 2004/12/14 23:31:26 joerg
published for new release 0.2.3
Revision 1.26 2004/12/14 23:17:05 joerg
published for new release 0.2.2
Revision 1.25 2004/12/14 22:42:22 joerg
allFiles: all sources have a Log CVS keyword at the end now.
*/