Placate all the compilers. Ugly.
[beanstalkd.git] / cutgen.c
blob907b59ed8d20ab4f5cfef361d0b4be46626dbe62
1 /*
2 * This file has been modified from the original CUT distribution.
4 * CUT 2.3-kr1
5 * Copyright (c) 2001-2002 Samuel A. Falvo II, William D. Tanksley
6 * See CUT-LICENSE.TXT for details.
8 * $Log: cutgen.c,v $
9 * Revision 1.4 2003/03/18 05:53:50 sfalvo
10 * ADD: cutgen.c: cut_exit() -- common exit point; returns proper error code
11 * at all times.
13 * FIX: cutgen.c: Factored all instances of exit() to invoke cut_exit()
14 * instead. This fixes the bug #703793.
16 * Revision 1.3 2003/03/13 04:27:54 sfalvo
17 * ADD: LICENSE.TXT -- zlib license
19 * ADD: README cut.h cutgen.c -- Changelog token for CVS
21 * FIX: test/bringup-failure -- reflects new usage for bringups and
22 * teardowns in CUT 2.2.
26 #include <stdio.h>
27 #include <string.h>
28 #include <stdlib.h>
29 #include <stdarg.h>
31 #include "util.h"
33 #define DO_NOT_PROCESS "..."
35 #define SEARCH_TOKEN_TEST "__CUT__"
36 #define SEARCH_TOKEN_BRINGUP "__CUT_BRINGUP__"
37 #define SEARCH_TOKEN_TAKEDOWN "__CUT_TAKEDOWN__"
39 #define MAX_SYMBOL_LENGTH 256 /* arbitrary */
40 #define MAX_LINE_LENGTH 1024 /* arbitrary */
42 #define SEARCH_TOKEN_TEST_LENGTH sizeof( SEARCH_TOKEN_TEST )-1
43 #define SEARCH_TOKEN_BRINGUP_LENGTH sizeof( SEARCH_TOKEN_BRINGUP )-1
45 #define terr(fmt, args...) do { fprintf(stderr, "\n"); twarn(fmt, ##args); exit(1); } while (0)
46 #define terrx(fmt, args...) do { fprintf(stderr, "\n"); twarnx(fmt, ##args); exit(1); } while (0)
48 typedef enum TestType {
49 TYPE_TEST = 0,
50 TYPE_BRINGUP = 1,
51 } TestType;
53 typedef struct TestItem {
54 char name[MAX_SYMBOL_LENGTH];
55 struct TestItem *next;
56 } TestItem;
58 typedef struct TestGroup {
59 char name[MAX_SYMBOL_LENGTH];
60 struct TestItem *tests;
61 struct TestGroup *next;
62 } TestGroup;
64 /* globals */
66 TestGroup *test_groups = 0;
67 FILE *outfile;
69 static int g_count, g_ready, g_index; /* Used by filename globbing support for windows */
70 static char **g_wildcards, g_fileName[MAX_LINE_LENGTH];
72 int NameAndTypeInTestList( char *name, TestType type )
74 TestItem *item;
75 TestGroup *group;
77 for (group = test_groups; group; group = group->next) {
78 if (!strcmp(group->name, name) && type == TYPE_BRINGUP) return 1;
79 for (item = group->tests; item; item = item->next) {
80 if (!strcmp(item->name, name)) return 1;
84 return 0;
87 void AppendToTestList( char *name, TestType type )
89 TestGroup *cur;
90 TestItem *newt;
92 if (type == TYPE_BRINGUP) {
93 struct TestGroup *new;
95 new = malloc(sizeof(struct TestGroup));
96 if (!new) terr("malloc");
98 new->tests = 0;
99 new->next = test_groups;
100 strcpy(new->name, name);
101 test_groups = new;
102 } else {
103 cur = test_groups;
104 if (!cur) terrx("no current test group");
106 newt = malloc(sizeof(struct TestItem));
107 if (!newt) terr("malloc");
109 newt->next = cur->tests;
110 strcpy(newt->name, name);
111 cur->tests = newt;
115 void InsertNameAndTypeIntoTestList( char *name, TestType type )
117 if ( !NameAndTypeInTestList( name, type ) )
118 AppendToTestList( name, type );
121 int CharacterIsDigit(char ch)
123 return ( ( ch >= '0') && ( ch <= '9' ) );
126 int CharacterIsUppercase(char ch)
128 return ( ( ch >= 'A' ) && ( ch <= 'Z' ) );
131 int CharacterIsLowercase(char ch)
133 return ( ( ch >= 'a' ) && ( ch <= 'z' ) );
136 int CharacterIsAlphabetic(char ch)
138 return CharacterIsUppercase(ch) || CharacterIsLowercase(ch) || ( ch == '_' );
141 int CharacterIsAlphanumeric( char ch )
143 return CharacterIsDigit(ch) || CharacterIsAlphabetic(ch);
146 void ProcessGenericFunction( char *line, int position,
147 TestType type, int tokenDisplacement )
149 char name[MAX_SYMBOL_LENGTH] = "";
150 int maxLength = strlen( line ) - 1, offset=0;
151 position = position + tokenDisplacement;
153 while ( CharacterIsAlphanumeric(line[position])
154 && (position<maxLength) && (offset<MAX_SYMBOL_LENGTH) )
156 name[offset++] = line[position++];
157 name[offset] = 0;
160 InsertNameAndTypeIntoTestList( name, type );
163 void ProcessBringupFunction( char *line, int position )
165 ProcessGenericFunction( line, position, TYPE_BRINGUP, SEARCH_TOKEN_BRINGUP_LENGTH );
168 void ProcessTestFunction( char *line, int position )
170 ProcessGenericFunction( line, position, TYPE_TEST, SEARCH_TOKEN_TEST_LENGTH );
174 int OffsetOfSubstring( char *line, char *token )
176 char *inset = strstr(line,token);
178 if ( !inset ) return -1;
179 else return inset - line;
182 void CallIfSubstringFound( char *line, char *token, void (*function)(char*,int) )
184 int index = OffsetOfSubstring( line, token );
185 if ( index != -1 )
186 function( line, index );
189 void ProcessSourceFile( char *filename )
191 FILE *source;
192 char line[MAX_LINE_LENGTH];
194 if( strcmp( filename, DO_NOT_PROCESS ) != 0 )
197 source = fopen(filename,"r");
199 while ( fgets(line,MAX_LINE_LENGTH,source) )
201 CallIfSubstringFound( line, SEARCH_TOKEN_BRINGUP, ProcessBringupFunction );
202 CallIfSubstringFound( line, SEARCH_TOKEN_TEST, ProcessTestFunction );
205 fclose(source);
209 void EmitExternDeclarationFor( char *name, char *prefix )
211 fprintf( outfile, "extern void %s%s( void );\n", prefix, name );
214 void Emit(char *text)
216 fprintf(outfile, "%s\n", text);
219 void BlankLine()
221 Emit( "" );
224 void ListExternalFunctions()
226 TestGroup *cur;
227 TestItem *item;
229 for (cur = test_groups; cur; cur = cur->next) {
230 EmitExternDeclarationFor(cur->name, SEARCH_TOKEN_BRINGUP);
231 EmitExternDeclarationFor(cur->name, SEARCH_TOKEN_TAKEDOWN);
232 for (item = cur->tests; item; item = item->next) {
233 EmitExternDeclarationFor(item->name, SEARCH_TOKEN_TEST);
236 BlankLine();
239 void ListHeaderFiles(void)
241 Emit(
242 "#include <string.h>\n"
243 "#include <stdlib.h>\n"
244 "#include <stdio.h>\n"
245 "#include <stdarg.h>\n"
246 "#include \"cut.h\"\n"
248 BlankLine();
249 BlankLine();
252 void EmitIndented(int indent,char *format, ...)
254 va_list v;
255 /* Print two spaces per level of indentation. */
256 fprintf( outfile, "%*s", indent*2, "" );
258 va_start(v,format);
259 vfprintf( outfile, format, v );
260 va_end(v);
262 fprintf( outfile, "\n" );
265 void EmitUnitTesterBody()
267 TestItem *test;
268 TestGroup *group;
270 Emit( "int main( int argc, char *argv[] )\n{" );
271 Emit( " if ( argc == 1 )" );
272 Emit( " cut_init(argv[0], -1 );" );
273 Emit( " else cut_init(argv[0], atoi( argv[1] ) );" );
274 BlankLine();
276 for (group = test_groups; group; group = group->next) {
277 for (test = group->tests; test; test = test->next) {
278 EmitIndented(1, "cut_run(%s, %s);", group->name, test->name);
282 BlankLine();
283 Emit( " cut_exit();\n" );
284 Emit( " return 0;\n}\n" );
287 void EmitCutCheck()
289 Emit( "/* Automatically generated: DO NOT MODIFY. */" );
290 ListHeaderFiles();
291 BlankLine();
292 ListExternalFunctions();
293 BlankLine();
294 EmitUnitTesterBody();
297 void FileName( char *base )
299 strncpy( g_fileName, base, MAX_LINE_LENGTH );
300 g_fileName[ MAX_LINE_LENGTH - 1 ] = 0;
303 int LoadArgument( void )
305 if ( g_index >= g_count )
306 return 0;
308 FileName( g_wildcards[g_index] );
309 g_index++; /* MUST come after FileName() call; bad code smell */
310 return 1;
313 void StartArguments( int starting, int count, char *array[] )
315 g_index = starting;
316 g_count = count;
317 g_wildcards = array;
319 g_ready = LoadArgument();
322 int NextArgument( void )
324 if( g_ready )
325 g_ready = LoadArgument();
327 return g_ready;
330 char *GetArgument( void )
332 if( g_ready )
333 return g_fileName;
335 return NULL;
338 void EstablishOutputFile( int argc, char *argv[] )
340 int i;
342 i = 0;
343 while( i < argc )
345 if( ( argv[i+1] != NULL ) && ( strcmp( argv[i], "-o" ) == 0 ) )
347 outfile = fopen( argv[i+1], "wb+" );
348 if( outfile == NULL )
349 fprintf( stderr, "ERROR: Can't open %s for writing.\n", argv[i+1] );
351 argv[i] = argv[i+1] = DO_NOT_PROCESS;
353 return;
356 i++;
359 outfile = stdout;
362 int main( int argc,char *argv[] )
364 char *filename;
366 if ( argc < 2 )
368 fprintf(
369 stderr,
370 "USAGE:\n"
371 " %s [options] <input file> [<input file> [...]]\n"
372 "\n"
373 "OPTIONS:\n"
374 " -o filename Specifies output file.\n"
375 "\n"
376 "NOTES:\n"
377 " If -o is left unspecified, output defaults to stdout.\n",
378 argv[0]
380 return 3;
383 EstablishOutputFile( argc, argv );
385 /* Skip the executable's name and the output filename. */
386 StartArguments(0,argc,argv);
388 /* Consume the rest of the arguments, one at a time. */
389 while ( NextArgument() )
391 filename = GetArgument();
393 if( strcmp( filename, DO_NOT_PROCESS ) )
395 fprintf( stderr, " - parsing '%s'... ", filename);
396 ProcessSourceFile( filename );
397 fprintf( stderr, "done.\n");
401 EmitCutCheck();
402 fflush(outfile);
403 fclose(outfile);
404 return 0;
408 * vim: tabstop=3 shiftwidth=3 expandtab