refactor
[beanstalkd.git] / cutgen.c
bloba0d24694c0d50aab07b0c4c22921843b21eacdc0
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>
30 #include <errno.h>
32 #define DO_NOT_PROCESS "..."
34 #define SEARCH_TOKEN_TEST "__CUT__"
35 #define SEARCH_TOKEN_BRINGUP "__CUT_BRINGUP__"
36 #define SEARCH_TOKEN_TAKEDOWN "__CUT_TAKEDOWN__"
38 #define MAX_SYMBOL_LENGTH 256 /* arbitrary */
39 #define MAX_LINE_LENGTH 1024 /* arbitrary */
41 #define SEARCH_TOKEN_TEST_LENGTH sizeof( SEARCH_TOKEN_TEST )-1
42 #define SEARCH_TOKEN_BRINGUP_LENGTH sizeof( SEARCH_TOKEN_BRINGUP )-1
44 #define terr(fmt, args...) do { fprintf(stderr, "\n"); twarn(fmt, ##args); exit(1); } while (0)
45 #define terrx(fmt, args...) do { fprintf(stderr, "\n"); twarnx(fmt, ##args); exit(1); } while (0)
47 #define twarn(fmt, args...) warn("%s:%d in %s: " fmt, \
48 __FILE__, __LINE__, __func__, ##args)
49 #define twarnx(fmt, args...) warnx("%s:%d in %s: " fmt, \
50 __FILE__, __LINE__, __func__, ##args)
52 typedef enum TestType {
53 TYPE_TEST = 0,
54 TYPE_BRINGUP = 1,
55 } TestType;
57 typedef struct TestItem {
58 char name[MAX_SYMBOL_LENGTH];
59 struct TestItem *next;
60 } TestItem;
62 typedef struct TestGroup {
63 char name[MAX_SYMBOL_LENGTH];
64 struct TestItem *tests;
65 struct TestGroup *next;
66 } TestGroup;
68 /* globals */
70 TestGroup *test_groups = 0;
71 FILE *outfile;
73 static int g_count, g_ready, g_index; /* Used by filename globbing support for windows */
74 static char **g_wildcards, g_fileName[MAX_LINE_LENGTH];
76 static void
77 vwarnx(const char *err, const char *fmt, va_list args)
79 if (fmt) {
80 vfprintf(stderr, fmt, args);
81 if (err) fprintf(stderr, ": %s", err);
83 fputc('\n', stderr);
86 static void
87 warn(const char *fmt, ...)
89 char *err = strerror(errno); /* must be done first thing */
90 va_list args;
92 va_start(args, fmt);
93 vwarnx(err, fmt, args);
94 va_end(args);
97 static void
98 warnx(const char *fmt, ...)
100 va_list args;
101 va_start(args, fmt);
102 vwarnx(NULL, fmt, args);
103 va_end(args);
107 int NameAndTypeInTestList( char *name, TestType type )
109 TestItem *item;
110 TestGroup *group;
112 for (group = test_groups; group; group = group->next) {
113 if (!strcmp(group->name, name) && type == TYPE_BRINGUP) return 1;
114 for (item = group->tests; item; item = item->next) {
115 if (!strcmp(item->name, name)) return 1;
119 return 0;
122 void AppendToTestList( char *name, TestType type )
124 TestGroup *cur;
125 TestItem *newt;
127 if (type == TYPE_BRINGUP) {
128 struct TestGroup *new;
130 new = malloc(sizeof(struct TestGroup));
131 if (!new) terr("malloc");
133 new->tests = 0;
134 new->next = test_groups;
135 strcpy(new->name, name);
136 test_groups = new;
137 } else {
138 cur = test_groups;
139 if (!cur) terrx("no current test group");
141 newt = malloc(sizeof(struct TestItem));
142 if (!newt) terr("malloc");
144 newt->next = cur->tests;
145 strcpy(newt->name, name);
146 cur->tests = newt;
150 void InsertNameAndTypeIntoTestList( char *name, TestType type )
152 if ( !NameAndTypeInTestList( name, type ) )
153 AppendToTestList( name, type );
156 int CharacterIsDigit(char ch)
158 return ( ( ch >= '0') && ( ch <= '9' ) );
161 int CharacterIsUppercase(char ch)
163 return ( ( ch >= 'A' ) && ( ch <= 'Z' ) );
166 int CharacterIsLowercase(char ch)
168 return ( ( ch >= 'a' ) && ( ch <= 'z' ) );
171 int CharacterIsAlphabetic(char ch)
173 return CharacterIsUppercase(ch) || CharacterIsLowercase(ch) || ( ch == '_' );
176 int CharacterIsAlphanumeric( char ch )
178 return CharacterIsDigit(ch) || CharacterIsAlphabetic(ch);
181 void ProcessGenericFunction( char *line, int position,
182 TestType type, int tokenDisplacement )
184 char name[MAX_SYMBOL_LENGTH] = "";
185 int maxLength = strlen( line ) - 1, offset=0;
186 position = position + tokenDisplacement;
188 while ( CharacterIsAlphanumeric(line[position])
189 && (position<maxLength) && (offset<MAX_SYMBOL_LENGTH) )
191 name[offset++] = line[position++];
192 name[offset] = 0;
195 InsertNameAndTypeIntoTestList( name, type );
198 void ProcessBringupFunction( char *line, int position )
200 ProcessGenericFunction( line, position, TYPE_BRINGUP, SEARCH_TOKEN_BRINGUP_LENGTH );
203 void ProcessTestFunction( char *line, int position )
205 ProcessGenericFunction( line, position, TYPE_TEST, SEARCH_TOKEN_TEST_LENGTH );
209 int OffsetOfSubstring( char *line, char *token )
211 char *inset = strstr(line,token);
213 if ( !inset ) return -1;
214 else return inset - line;
217 void CallIfSubstringFound( char *line, char *token, void (*function)(char*,int) )
219 int index = OffsetOfSubstring( line, token );
220 if ( index != -1 )
221 function( line, index );
224 void ProcessSourceFile( char *filename )
226 FILE *source;
227 char line[MAX_LINE_LENGTH];
229 if( strcmp( filename, DO_NOT_PROCESS ) != 0 )
232 source = fopen(filename,"r");
234 while ( fgets(line,MAX_LINE_LENGTH,source) )
236 CallIfSubstringFound( line, SEARCH_TOKEN_BRINGUP, ProcessBringupFunction );
237 CallIfSubstringFound( line, SEARCH_TOKEN_TEST, ProcessTestFunction );
240 fclose(source);
244 void EmitExternDeclarationFor( char *name, char *prefix )
246 fprintf( outfile, "extern void %s%s( void );\n", prefix, name );
249 void Emit(char *text)
251 fprintf(outfile, "%s\n", text);
254 void BlankLine()
256 Emit( "" );
259 void ListExternalFunctions()
261 TestGroup *cur;
262 TestItem *item;
264 for (cur = test_groups; cur; cur = cur->next) {
265 EmitExternDeclarationFor(cur->name, SEARCH_TOKEN_BRINGUP);
266 EmitExternDeclarationFor(cur->name, SEARCH_TOKEN_TAKEDOWN);
267 for (item = cur->tests; item; item = item->next) {
268 EmitExternDeclarationFor(item->name, SEARCH_TOKEN_TEST);
271 BlankLine();
274 void ListHeaderFiles(void)
276 Emit(
277 "#include <string.h>\n"
278 "#include <stdlib.h>\n"
279 "#include <stdio.h>\n"
280 "#include <stdarg.h>\n"
281 "#include \"cut.h\"\n"
283 BlankLine();
284 BlankLine();
287 void EmitIndented(int indent,char *format, ...)
289 va_list v;
290 /* Print two spaces per level of indentation. */
291 fprintf( outfile, "%*s", indent*2, "" );
293 va_start(v,format);
294 vfprintf( outfile, format, v );
295 va_end(v);
297 fprintf( outfile, "\n" );
300 void EmitUnitTesterBody()
302 TestItem *test;
303 TestGroup *group;
305 Emit( "int main( int argc, char *argv[] )\n{" );
306 Emit( " if ( argc == 1 )" );
307 Emit( " cut_init(argv[0], -1 );" );
308 Emit( " else cut_init(argv[0], atoi( argv[1] ) );" );
309 BlankLine();
311 for (group = test_groups; group; group = group->next) {
312 for (test = group->tests; test; test = test->next) {
313 EmitIndented(1, "cut_run(%s, %s);", group->name, test->name);
317 BlankLine();
318 Emit( " cut_exit();\n" );
319 Emit( " return 0;\n}\n" );
322 void EmitCutCheck()
324 Emit( "/* Automatically generated: DO NOT MODIFY. */" );
325 ListHeaderFiles();
326 BlankLine();
327 ListExternalFunctions();
328 BlankLine();
329 EmitUnitTesterBody();
332 void FileName( char *base )
334 strncpy( g_fileName, base, MAX_LINE_LENGTH );
335 g_fileName[ MAX_LINE_LENGTH - 1 ] = 0;
338 int LoadArgument( void )
340 if ( g_index >= g_count )
341 return 0;
343 FileName( g_wildcards[g_index] );
344 g_index++; /* MUST come after FileName() call; bad code smell */
345 return 1;
348 void StartArguments( int starting, int count, char *array[] )
350 g_index = starting;
351 g_count = count;
352 g_wildcards = array;
354 g_ready = LoadArgument();
357 int NextArgument( void )
359 if( g_ready )
360 g_ready = LoadArgument();
362 return g_ready;
365 char *GetArgument( void )
367 if( g_ready )
368 return g_fileName;
370 return NULL;
373 void EstablishOutputFile( int argc, char *argv[] )
375 int i;
377 i = 0;
378 while( i < argc )
380 if( ( argv[i+1] != NULL ) && ( strcmp( argv[i], "-o" ) == 0 ) )
382 outfile = fopen( argv[i+1], "wb+" );
383 if( outfile == NULL )
384 fprintf( stderr, "ERROR: Can't open %s for writing.\n", argv[i+1] );
386 argv[i] = argv[i+1] = DO_NOT_PROCESS;
388 return;
391 i++;
394 outfile = stdout;
397 int main( int argc,char *argv[] )
399 char *filename;
401 if ( argc < 2 )
403 fprintf(
404 stderr,
405 "USAGE:\n"
406 " %s [options] <input file> [<input file> [...]]\n"
407 "\n"
408 "OPTIONS:\n"
409 " -o filename Specifies output file.\n"
410 "\n"
411 "NOTES:\n"
412 " If -o is left unspecified, output defaults to stdout.\n",
413 argv[0]
415 return 3;
418 EstablishOutputFile( argc, argv );
420 /* Skip the executable's name and the output filename. */
421 StartArguments(0,argc,argv);
423 /* Consume the rest of the arguments, one at a time. */
424 while ( NextArgument() )
426 filename = GetArgument();
428 if( strcmp( filename, DO_NOT_PROCESS ) )
430 fprintf( stderr, " - parsing '%s'... ", filename);
431 ProcessSourceFile( filename );
432 fprintf( stderr, "done.\n");
436 EmitCutCheck();
437 fflush(outfile);
438 fclose(outfile);
439 return 0;
443 * vim: tabstop=3 shiftwidth=3 expandtab