siliconBrainLib.h
#ifndef siliconBrainLib_alreadyIncluded
#define siliconBrainLib_alreadyIncluded
/******************************************** -*-c-*- ***********************************************/
/*                                                                                                  */
/* siliconBrainLib.h:                                                                               */
/*                                                                                                  */
/****************************************************************************************************/

/****************************************************************************************************/
/*                                                                                                  */
/*     Copyright (C) 2004 Joerg Kunze                                                               */
/*                                                                                                  */
/*     This file is part of siliconBrainLib.                                                        */
/*                                                                                                  */
/*     siliconBrainLib 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.                                                          */
/*                                                                                                  */
/*     siliconBrainLib 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                    */
/*                                                                                                  */
/****************************************************************************************************/

// char *siliconBrainRelease       = "$siliconBrainRelease: 0.0.4 $";
// char *siliconBrainRcsIdentifier = "$Id: siliconBrainLib.h,v 1.25 2004/12/14 23:09:01 joerg Exp $";
// char *siliconBrainSaveStamp     = "$siliconBrainSaveStamp: 2004/11/08 00:59:11, Joerg Kunze$";

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
#include <unistd.h>

#include <obstack.h>

#include "glib.h"

/****************************************************************************************************/
/*                                                                                                  */
/* Memory:                                                                                          */
/*                                                                                                  */
/****************************************************************************************************/
typedef struct obstack Obstack;

#define obstack_chunk_alloc malloc
#define obstack_chunk_free  free

typedef Obstack Memory;

#define memoryInit(      memory ) obstack_init( &(memory) )
#define memoryDestroy(   memory ) obstack_free( &(memory), 0 )
#define memoryAllocate(  memory, size         ) obstack_alloc( &(memory), (size) )
#define memoryDuplicate( memory, source, size ) obstack_copy( &(memory), (source), (size) )

/****************************************************************************************************/
/*                                                                                                  */
/* String:                                                                                          */
/*                                                                                                  */
/****************************************************************************************************/
typedef struct {
   char   *begin;
   size_t  length;
   size_t  capacity;
} String;

#define c( cString ) ((String){ cString, sizeof( (cString) ) - 1, sizeof( (cString) ) - 1 })
#define string( cString ) ((String){ cString, strlen( (cString) ), 0  })

static const String stringNull = { 0, 0, 0 };

#define copy( memory, target, source ) {\
   String *_target = &(target), *_source=&(source);\
   if( _target->capacity < _source->length+1 ) _target->begin = memoryAllocate( (memory), _target->capacity = (_source->length+1) << 1 );\
   memcpy( _target->begin, _source->begin, _target->length = _source->length );\
   _target->begin[ _target->length ] = 0;\
}

#define copy_a( target, source ) {\
   String *_target = &(target), *_source=&(source);\
   if( _target->capacity < _source->length+1 ) _target->begin = alloca( _target->capacity = (_source->length+1) << 1 );\
   memcpy( _target->begin, _source->begin, _target->length = _source->length );\
   _target->begin[ _target->length ] = 0;\
}

#define collect_a( target, ...) {\
   String *_target = &(target);\
   String _source[] = { __VA_ARGS__, stringNull };\
   String *single;\
   for( _target->length = 0, single = _source; single->begin; ++single ) _target->length +=single->length;\
   if( _target->capacity < _target->length+1 ) _target->begin = alloca( _target->capacity = (_target->length+1) << 1 );\
   char *current;\
   for( current = _target->begin, single = _source; single->begin; ++single ) current = mempcpy( current, single->begin, single->length );\
   _target->begin[ _target->length ] = 0;\
 }

#define toC( memory, source ) ({\
   String *_source=&(source);\
   char   *_target;\
   if( _source->begin[ _source->length ] == 0 ) {\
      _target = _source->begin;\
   } else {\
      _target = memoryAllocate( (memory), _source->length+1 );\
      memcpy( _target, _source->begin, _source->length );\
      _target[ _source->length ] = 0;\
   }\
   _target;\
})

#define toCa( source ) ({\
  String *_source=&(source);\
  char   *_target;\
   if( _source->begin[ _source->length ] == 0 ) {\
      _target = _source->begin;\
   } else {\
     _target = alloca( _source->length+1 );\
     memcpy( _target, _source->begin, _source->length );\
     _target[ _source->length ] = 0;\
   }\
   _target;\
})

#define equal( left, right ) ({ \
  String *_left = &(left), *_right = &(right);\
  _left->length == _right->length && !memcmp( _left->begin, _right->begin, _left->length );\
})

#define print( source ) ({ String *_source = &(source); fwrite( _source->begin, _source->length, 1, stdout ); })
#define println( source ) ({print( source ); putchar( '\n' ); })

/****************************************************************************************************/
/*                                                                                                  */
/* type:                                                                                            */
/*                                                                                                  */
/****************************************************************************************************/
typedef enum {
   end   = 0,
   start = 1
} StartEnd;

/****************************************************************************************************/
/*                                                                                                  */
/* StringBuffer:                                                                                    */
/*                                                                                                  */
/****************************************************************************************************/
typedef struct StringBuffer {
   Obstack *obstack;
   int      length;
   char    *value;
} StringBuffer;

void  stringBufferInit  ( StringBuffer *stringBuffer, Obstack *obstack   );
char *stringBufferAlloc ( StringBuffer *stringBuffer, unsigned size      );

/****************************************************************************************************/
/*                                                                                                  */
/* StringStack:                                                                                     */
/*                                                                                                  */
/****************************************************************************************************/
typedef struct StringStack {
   GStringChunk *chunk;
   GPtrArray    *strings;
} StringStack;

/****************************************************************************************************/
/*                                                                                                  */
/* convenience:                                                                                     */
/*                                                                                                  */
/****************************************************************************************************/
#define  printu(       string ) fputs( (string), stdout )
#define fprintu( file, string ) fputs( (string), (file) )

#define strequ( target, source ) (!strcmp( (target), (source) ) )

/****************************************************************************************************/
/*                                                                                                  */
/* string:                                                                                          */
/*                                                                                                  */
/****************************************************************************************************/
extern bool stringToBool( const char *boolString );
extern int osprintf( Obstack *obstack, char **target, const char *template, ... );

/****************************************************************************************************/
/*                                                                                                  */
/* print:                                                                                           */
/*                                                                                                  */
/****************************************************************************************************/
typedef struct SiliconBrainPrinter {
   StringStack tagNameStack;
   bool        insideTag;
   bool        insideText;
   bool        insideComment;
   bool        doIndent;
   int         indent;
   int         nestingDepth;

   char       *tagEndTagBeforeNewTag;
   char       *tagStartTag;

   char       *attributeEndTagBeforeAttribute;
   bool        attributeIsOutsideTag;
   char       *attributeNameStart;
   char       *attributeNameEnd;
   char       *attributeValueEnd;

   char       *endInsideTag;
   char       *endTagStart;
   char       *endTagEnd;

   char       *textEndTagBeforeText;
   char       *textValueEnd;

   char       *commentStart;
   char       *commentEnd;
   char       *commentIndent;

   char       *boolTrue;
   char       *boolFalse;

   void       (*printEscapedChar)( struct SiliconBrainPrinter *printer, char characterToPrint );
   void       (*printCommentChar)( struct SiliconBrainPrinter *printer, char characterToPrint );

   void       (*printCharacter  )( struct SiliconBrainPrinter *printer, char characterToPrint );
   void       (*printString     )( struct SiliconBrainPrinter *printer, const char *stringToPrint    );

   int         indentation;
   bool        deferredIndentation;

   const char *stringColor;

   void       (*quoter)(struct SiliconBrainPrinter *printer, const char *source );

   const char *nameOfRootTag;

   StringBuffer namePrefix;

   void       (*onRootTag)( struct SiliconBrainPrinter *printer, StartEnd mode );

   struct obstack obstack;

   char       *usageDescription;

} SiliconBrainPrinter;

int siliconBrainPrinterInit     ( SiliconBrainPrinter *printer, int argc, const char *argv[]        );

int siliconBrainPrinterTag      ( SiliconBrainPrinter *printer, const char *name                    );
int siliconBrainPrinterText     ( SiliconBrainPrinter *printer, const char *value                   );
int siliconBrainPrinterAttribute( SiliconBrainPrinter *printer, const char *name, const char *value );

int siliconBrainPrinterEnd      ( SiliconBrainPrinter *printer                                      );
int siliconBrainPrinterDestroy  ( SiliconBrainPrinter *printer                                      );
int siliconBrainPrinterComment  ( SiliconBrainPrinter *printer, const char *value                   );

int siliconBrainPrinterKey      ( SiliconBrainPrinter *printer, const char *key , const char *value );
int siliconBrainPrinterKeyBool  ( SiliconBrainPrinter *printer, const char *key , bool        value );

#ifdef siliconBrainPrintShortNames
   #define tag(       name        ) siliconBrainPrinterTag      ( &siliconBrainPrinter, name        )
   #define end(                   ) siliconBrainPrinterEnd      ( &siliconBrainPrinter              )
   #define attribute( name, value ) siliconBrainPrinterAttribute( &siliconBrainPrinter, name, value )
   #define text(      value       ) siliconBrainPrinterText     ( &siliconBrainPrinter, value       )
   #define destroy(               ) siliconBrainPrinterDestroy  ( &siliconBrainPrinter              )
   #define comment(   value       ) siliconBrainPrinterComment  ( &siliconBrainPrinter, value       )
   #define key(       key , value ) siliconBrainPrinterKey      ( &siliconBrainPrinter, key , value )
   #define keyBool(   key , value ) siliconBrainPrinterKeyBool  ( &siliconBrainPrinter, key , value )
#endif

#endif