Logo Search packages:      
Sourcecode: beanstalkd version File versions  Download package

cutgen.c

/*
 * This file has been modified from the original CUT distribution.
 *
 * CUT 2.3-kr1
 * Copyright (c) 2001-2002 Samuel A. Falvo II, William D. Tanksley
 * See CUT-LICENSE.TXT for details.
 *
 * $Log: cutgen.c,v $
 * Revision 1.4  2003/03/18 05:53:50  sfalvo
 * ADD: cutgen.c: cut_exit() -- common exit point; returns proper error code
 * at all times.
 *
 * FIX: cutgen.c: Factored all instances of exit() to invoke cut_exit()
 * instead.  This fixes the bug #703793.
 *
 * Revision 1.3  2003/03/13 04:27:54  sfalvo
 * ADD: LICENSE.TXT -- zlib license
 *
 * ADD: README cut.h cutgen.c -- Changelog token for CVS
 *
 * FIX: test/bringup-failure -- reflects new usage for bringups and
 * teardowns in CUT 2.2.
 *
 */

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>

#include "util.h"

#define DO_NOT_PROCESS        "..."

#define SEARCH_TOKEN_TEST     "__CUT__"
#define SEARCH_TOKEN_BRINGUP  "__CUT_BRINGUP__"
#define SEARCH_TOKEN_TAKEDOWN "__CUT_TAKEDOWN__"

#define MAX_SYMBOL_LENGTH 256  /* arbitrary */
#define MAX_LINE_LENGTH   1024 /* arbitrary */

#define SEARCH_TOKEN_TEST_LENGTH       sizeof( SEARCH_TOKEN_TEST )-1
#define SEARCH_TOKEN_BRINGUP_LENGTH    sizeof( SEARCH_TOKEN_BRINGUP )-1

#define terr(fmt, args...) do { fprintf(stderr, "\n"); twarn(fmt, ##args); exit(1); } while (0)
#define terrx(fmt, args...) do { fprintf(stderr, "\n"); twarnx(fmt, ##args); exit(1); } while (0)

typedef enum TestType {
   TYPE_TEST = 0,
   TYPE_BRINGUP = 1,
} TestType;

typedef struct TestItem {
   char name[MAX_SYMBOL_LENGTH];
   struct TestItem *next;
} TestItem;

typedef struct TestGroup {
   char name[MAX_SYMBOL_LENGTH];
   struct TestItem *tests;
   struct TestGroup *next;
} TestGroup;

/* globals */

TestGroup *test_groups = 0;
FILE *outfile;

static int g_count, g_ready, g_index;  /* Used by filename globbing support for windows */
static char **g_wildcards, g_fileName[MAX_LINE_LENGTH];

int NameAndTypeInTestList( char *name, TestType type )
{
   TestItem *item;
   TestGroup *group;

   for (group = test_groups; group; group = group->next) {
      if (!strcmp(group->name, name) && type == TYPE_BRINGUP) return 1;
      for (item = group->tests; item; item = item->next) {
         if (!strcmp(item->name, name)) return 1;
      }
   }

   return 0;
}

void AppendToTestList( char *name, TestType type )
{
   TestGroup *cur;
   TestItem *newt;

   if (type == TYPE_BRINGUP) {
      struct TestGroup *new;

      new = malloc(sizeof(struct TestGroup));
      if (!new) terr("malloc");

      new->tests = 0;
      new->next = test_groups;
      strcpy(new->name, name);
      test_groups = new;
   } else {
      cur = test_groups;
      if (!cur) terrx("no current test group");

      newt = malloc(sizeof(struct TestItem));
      if (!newt) terr("malloc");

      newt->next = cur->tests;
      strcpy(newt->name, name);
      cur->tests = newt;
   }
}

void InsertNameAndTypeIntoTestList( char *name, TestType type )
{
    if ( !NameAndTypeInTestList( name, type ) )
        AppendToTestList( name, type );
}

int CharacterIsDigit(char ch)
{
    return ( ( ch >= '0') && ( ch <= '9' ) );
}

int CharacterIsUppercase(char ch)
{
    return ( ( ch >= 'A' ) && ( ch <= 'Z' ) );
}

int CharacterIsLowercase(char ch)
{
    return ( ( ch >= 'a' ) && ( ch <= 'z' ) );
}

int CharacterIsAlphabetic(char ch)
{
    return CharacterIsUppercase(ch) || CharacterIsLowercase(ch) || ( ch == '_' );
}

int CharacterIsAlphanumeric( char ch )
{
    return CharacterIsDigit(ch) || CharacterIsAlphabetic(ch);
}

void ProcessGenericFunction( char *line, int position,
                            TestType type, int tokenDisplacement )
{
    char name[MAX_SYMBOL_LENGTH] = "";
    int maxLength = strlen( line ) - 1, offset=0;
    position = position + tokenDisplacement;

    while ( CharacterIsAlphanumeric(line[position])
       && (position<maxLength) && (offset<MAX_SYMBOL_LENGTH) )
    {
        name[offset++] = line[position++];
        name[offset] = 0;
    }

    InsertNameAndTypeIntoTestList( name, type );
}

void ProcessBringupFunction( char *line, int position )
{
    ProcessGenericFunction( line, position, TYPE_BRINGUP, SEARCH_TOKEN_BRINGUP_LENGTH );
}

void ProcessTestFunction( char *line, int position )
{
    ProcessGenericFunction( line, position, TYPE_TEST, SEARCH_TOKEN_TEST_LENGTH );
}


int OffsetOfSubstring( char *line, char *token )
{
    char *inset = strstr(line,token);

    if ( !inset ) return -1;
    else return inset - line;
}

void CallIfSubstringFound( char *line, char *token, void (*function)(char*,int) )
{
    int index = OffsetOfSubstring( line, token );
    if ( index != -1 )
        function( line, index );
}

void ProcessSourceFile( char *filename )
{
   FILE *source;
   char line[MAX_LINE_LENGTH];

   if( strcmp( filename, DO_NOT_PROCESS ) != 0 )
   {

      source = fopen(filename,"r");

      while ( fgets(line,MAX_LINE_LENGTH,source) )
      {
         CallIfSubstringFound( line, SEARCH_TOKEN_BRINGUP, ProcessBringupFunction );
         CallIfSubstringFound( line, SEARCH_TOKEN_TEST, ProcessTestFunction );
      }

      fclose(source);
   }
}

void EmitExternDeclarationFor( char *name, char *prefix )
{
    fprintf( outfile, "extern void %s%s( void );\n", prefix, name );
}

void Emit(char *text)
{
   fprintf(outfile, "%s\n", text);
}

void BlankLine()
{
    Emit( "" );
}

void ListExternalFunctions()
{
   TestGroup *cur;
   TestItem *item;

   for (cur = test_groups; cur; cur = cur->next) {
       EmitExternDeclarationFor(cur->name, SEARCH_TOKEN_BRINGUP);
       EmitExternDeclarationFor(cur->name, SEARCH_TOKEN_TAKEDOWN);
       for (item = cur->tests; item; item = item->next) {
          EmitExternDeclarationFor(item->name, SEARCH_TOKEN_TEST);
       }
   }
   BlankLine();
}

void ListHeaderFiles(void)
{
    Emit(
        "#include <string.h>\n"
        "#include <stdlib.h>\n"
        "#include <stdio.h>\n"
        "#include <stdarg.h>\n"
        "#include \"cut.h\"\n"
    );
    BlankLine();
    BlankLine();
}

void EmitIndented(int indent,char *format, ...)
{
   va_list v;
   /* Print two spaces per level of indentation. */
   fprintf( outfile, "%*s", indent*2, "" );

   va_start(v,format);
   vfprintf( outfile, format, v );
   va_end(v);

   fprintf( outfile, "\n" );
}

void EmitUnitTesterBody()
{
    TestItem *test;
    TestGroup *group;

    Emit( "int main( int argc, char *argv[] )\n{" );
    Emit( "  if ( argc == 1 )" );
    Emit( "    cut_init(argv[0], -1 );" );
    Emit( "  else cut_init(argv[0], atoi( argv[1] ) );" );
    BlankLine();

    for (group = test_groups; group; group = group->next) {
       for (test = group->tests; test; test = test->next) {
          EmitIndented(1, "cut_run(%s, %s);", group->name, test->name);
       }
    }

    BlankLine();
    Emit( "  cut_exit();\n" );
    Emit( "  return 0;\n}\n" );
}

void EmitCutCheck()
{
    Emit( "/* Automatically generated: DO NOT MODIFY. */" );
    ListHeaderFiles();
    BlankLine();
    ListExternalFunctions();
    BlankLine();
    EmitUnitTesterBody();
}

void FileName( char *base )
{
    strncpy( g_fileName, base, MAX_LINE_LENGTH );
    g_fileName[ MAX_LINE_LENGTH - 1 ] = 0;
}

int LoadArgument( void )
{
   if ( g_index >= g_count )
      return 0;

   FileName( g_wildcards[g_index] );
   g_index++;  /* MUST come after FileName() call; bad code smell */
   return 1;
}

void StartArguments( int starting, int count, char *array[] )
{
   g_index = starting;
   g_count = count;
   g_wildcards = array;

   g_ready = LoadArgument();
}

int NextArgument( void )
{
   if( g_ready )
      g_ready = LoadArgument();

   return g_ready;
}

char *GetArgument( void )
{
   if( g_ready )
      return g_fileName;

   return NULL;
}

void EstablishOutputFile( int argc, char *argv[] )
{
   int i;

   i = 0;
   while( i < argc )
   {
      if( ( argv[i+1] != NULL ) && ( strcmp( argv[i], "-o" ) == 0 ) )
      {
         outfile = fopen( argv[i+1], "wb+" );
         if( outfile == NULL )
            fprintf( stderr, "ERROR: Can't open %s for writing.\n", argv[i+1] );

         argv[i] = argv[i+1] = DO_NOT_PROCESS;

         return;
      }

      i++;
   }

   outfile = stdout;
}

int main( int argc,char *argv[] )
{
   char *filename;

   if ( argc < 2 )
   {
      fprintf(
              stderr,
              "USAGE:\n"
              "   %s [options] <input file> [<input file> [...]]\n"
              "\n"
              "OPTIONS:\n"
              "   -o filename   Specifies output file.\n"
              "\n"
              "NOTES:\n"
              "   If -o is left unspecified, output defaults to stdout.\n",
              argv[0]
             );
      return 3;
   }

   EstablishOutputFile( argc, argv );

   /* Skip the executable's name and the output filename. */
   StartArguments(0,argc,argv);

   /* Consume the rest of the arguments, one at a time. */
   while ( NextArgument() )
   {
      filename = GetArgument();

      if( strcmp( filename, DO_NOT_PROCESS ) )
      {
         fprintf( stderr, "  - parsing '%s'... ", filename);
         ProcessSourceFile( filename );
         fprintf( stderr, "done.\n");
      }
   }

   EmitCutCheck();
   fflush(outfile);
   fclose(outfile);
   return 0;
}

/*
 * vim: tabstop=3 shiftwidth=3 expandtab
 */


Generated by  Doxygen 1.6.0   Back to index