2 * This file has been modified from the original CUT distribution.
5 * Copyright (c) 2001-2002 Samuel A. Falvo II, William D. Tanksley
6 * See CUT-LICENSE.TXT for details.
9 * Revision 1.4 2003/03/18 05:53:50 sfalvo
10 * ADD: cutgen.c: cut_exit() -- common exit point; returns proper error code
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.
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
{
57 typedef struct TestItem
{
58 char name
[MAX_SYMBOL_LENGTH
];
59 struct TestItem
*next
;
62 typedef struct TestGroup
{
63 char name
[MAX_SYMBOL_LENGTH
];
64 struct TestItem
*tests
;
65 struct TestGroup
*next
;
70 TestGroup
*test_groups
= 0;
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
];
77 vwarnx(const char *err
, const char *fmt
, va_list args
)
80 vfprintf(stderr
, fmt
, args
);
81 if (err
) fprintf(stderr
, ": %s", err
);
87 warn(const char *fmt
, ...)
89 char *err
= strerror(errno
); /* must be done first thing */
93 vwarnx(err
, fmt
, args
);
98 warnx(const char *fmt
, ...)
102 vwarnx(NULL
, fmt
, args
);
107 int NameAndTypeInTestList( char *name
, TestType type
)
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;
122 void AppendToTestList( char *name
, TestType type
)
127 if (type
== TYPE_BRINGUP
) {
128 struct TestGroup
*new;
130 new = malloc(sizeof(struct TestGroup
));
131 if (!new) terr("malloc");
134 new->next
= test_groups
;
135 strcpy(new->name
, name
);
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
);
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
++];
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
);
221 function( line
, index
);
224 void ProcessSourceFile( char *filename
)
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
);
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
);
259 void ListExternalFunctions()
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
);
274 void ListHeaderFiles(void)
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"
287 void EmitIndented(int indent
,char *format
, ...)
290 /* Print two spaces per level of indentation. */
291 fprintf( outfile
, "%*s", indent
*2, "" );
294 vfprintf( outfile
, format
, v
);
297 fprintf( outfile
, "\n" );
300 void EmitUnitTesterBody()
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] ) );" );
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
);
318 Emit( " cut_exit();\n" );
319 Emit( " return 0;\n}\n" );
324 Emit( "/* Automatically generated: DO NOT MODIFY. */" );
327 ListExternalFunctions();
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
)
343 FileName( g_wildcards
[g_index
] );
344 g_index
++; /* MUST come after FileName() call; bad code smell */
348 void StartArguments( int starting
, int count
, char *array
[] )
354 g_ready
= LoadArgument();
357 int NextArgument( void )
360 g_ready
= LoadArgument();
365 char *GetArgument( void )
373 void EstablishOutputFile( int argc
, char *argv
[] )
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
;
397 int main( int argc
,char *argv
[] )
406 " %s [options] <input file> [<input file> [...]]\n"
409 " -o filename Specifies output file.\n"
412 " If -o is left unspecified, output defaults to stdout.\n",
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");
443 * vim: tabstop=3 shiftwidth=3 expandtab