2 * Generate a file with test registrations from a list
3 * of files in a directory.
4 * Casper S. Hornstrup <chorns@users.sourceforge.net>
20 #include <sys/types.h>
28 #define DIR_SEPARATOR_CHAR '/'
29 #define DIR_SEPARATOR_STRING "/"
31 #define DIR_SEPARATOR_CHAR '\\'
32 #define DIR_SEPARATOR_STRING "\\"
38 static char *makefile
;
39 static char *exestubfile
;
42 convert_path(char* origpath
)
47 /* for no good reason, i'm having trouble getting gcc to link strdup */
48 //newpath = strdup(origpath);
49 newpath
= malloc(strlen(origpath
)+1);
50 strcpy(newpath
, origpath
);
53 while (newpath
[i
] != 0)
56 if (newpath
[i
] == '\\')
62 if (newpath
[i
] == '/')
74 write_line(char *line
)
79 memset(buf
, 0, sizeof(buf
));
81 /* Terminate the line */
82 buf
[strlen(buf
)] = '\r';
83 buf
[strlen(buf
)] = '\n';
85 n_out
= fwrite(&buf
[0], 1, strlen(buf
), out
);
89 change_extension(char *filenamebuffer
,
95 if (newextension
== NULL
)
97 strcpy(filenamebuffer
, filename
);
101 ptr
= strrchr(filename
, '.');
104 strncpy(filenamebuffer
, filename
, ptr
- filename
);
105 filenamebuffer
[ptr
- filename
] = 0;
106 strcat(filenamebuffer
, newextension
);
110 strcpy(filenamebuffer
, filename
);
111 strcat(filenamebuffer
, newextension
);
116 get_test_name(char *filename
,
121 strcpy(testname
, filename
);
123 i
= strlen(testname
);
124 while (i
> 0 && testname
[i
] != '.')
133 /* Make a capital first letter and make all other letters lower case */
134 testname
[0] = toupper(testname
[0]);
135 if (!((testname
[0] >= 'A' && testname
[0] <= 'Z') ||
136 (testname
[0] >= '0' && testname
[0] <= '9')))
141 while (i
< strlen(testname
))
143 testname
[i
] = tolower(testname
[i
]);
144 if (!((testname
[i
] >= 'a' && testname
[i
] <= 'z') ||
145 (testname
[i
] >= '0' && testname
[i
] <= '9')))
154 * filename - name of file to make registrations for
155 * type - type of registration (0 = prototype, 1 = call, 2 = makefile)
158 register_test(char *filename
,
165 char filenamebuffer
[MAX_PATH
];
168 i
= strlen(filename
);
169 while (i
> 0 && filename
[i
] != '.')
175 memset(ext
, 0, sizeof(ext
));
176 strncpy(&ext
[0], &filename
[i
], strlen(&filename
[i
]));
178 if ((strncmp(ext
, ".c", 2) != 0) && (strncmp(ext
, ".C", 2) != 0))
188 memset(testname
, 0, sizeof(testname
));
189 get_test_name(filename
, testname
);
193 sprintf(regtest
, "extern int %sTest(int Command, char *Buffer);", testname
);
198 sprintf(call
, "%sTest", testname
);
199 sprintf(regtest
, " AddTest((TestRoutine)%s);", call
);
204 change_extension(filenamebuffer
, filename
, ".o");
205 sprintf(regtest
, "%s \\", filenamebuffer
);
215 make_file_list (int type
)
217 struct _finddata_t f
;
219 char searchbuf
[MAX_PATH
];
221 strcpy(searchbuf
, path
);
222 strcat(searchbuf
, "*.*");
223 findhandle
=_findfirst(searchbuf
, &f
);
224 if (findhandle
!= -1)
228 if (f
.attrib
& _A_SUBDIR
)
230 /* Skip subdirectories */
234 register_test(f
.name
, type
);
236 while (_findnext(findhandle
, &f
) == 0);
237 _findclose(findhandle
);
245 make_file_list (int type
)
248 struct dirent
*entry
;
253 dirp
= opendir(path
);
256 while ((entry
= readdir(dirp
)) != NULL
)
258 if (strcmp(entry
->d_name
, ".") == 0 || strcmp(entry
->d_name
, "..") == 0)
259 continue; // skip self and parent
261 if (entry
->d_type
== DT_REG
) // normal file
263 // Check for an absolute path
264 if (path
[0] == DIR_SEPARATOR_CHAR
)
267 strcat(buf
, DIR_SEPARATOR_STRING
);
268 strcat(buf
, entry
->d_name
);
272 getcwd(buf
, sizeof(buf
));
273 strcat(buf
, DIR_SEPARATOR_STRING
);
275 strcat(buf
, entry
->d_name
);
278 if (stat(buf
, &stbuf
) == -1)
280 printf("Can't access '%s' (%s)\n", buf
, strerror(errno
));
284 if (S_ISDIR(stbuf
.st_mode
))
286 /* Skip subdirectories */
290 register_test(entry
->d_name
, type
);
297 printf("Can't open %s\n", path
);
303 dirp
= opendir(path
);
306 while ((entry
= readdir(dirp
)) != NULL
)
308 if (strcmp(entry
->d_name
, ".") == 0 || strcmp(entry
->d_name
, "..") == 0)
309 continue; // skip self and parent
311 // Check for an absolute path
312 if (path
[0] == DIR_SEPARATOR_CHAR
)
315 strcat(buf
, DIR_SEPARATOR_STRING
);
316 strcat(buf
, entry
->d_name
);
320 getcwd(buf
, sizeof(buf
));
321 strcat(buf
, DIR_SEPARATOR_STRING
);
323 strcat(buf
, entry
->d_name
);
326 if (stat(buf
, &stbuf
) == -1)
328 printf("Can't access '%s' (%s)\n", buf
, strerror(errno
));
332 if (S_ISDIR(stbuf
.st_mode
))
334 /* Skip subdirectories */
338 register_test(entry
->d_name
, type
);
344 printf("Can't open %s\n", path
);
354 is_file_changed(char *filename
,
362 file
= fopen(filename
, "rb");
368 fseek(file
, 0, SEEK_END
);
370 fseek(file
, 0, SEEK_SET
);
376 filecontent
= malloc(size
);
377 if (filecontent
== NULL
)
383 n
= fread(filecontent
, 1, size
, file
);
385 if (n
!= strlen(content
))
392 if (strcmp(content
, filecontent
) != 0)
407 write_file_if_changed(char *filename
,
413 if (is_file_changed(filename
, content
) == 0)
418 file
= fopen(filename
, "wb");
424 n
= fwrite(content
, 1, strlen(content
), file
);
431 static char EXESTUB
[] =
432 "/* This file is autogenerated. */\n"
434 "#include \"regtests.h\"\n"
437 "ConsoleWrite(char *Buffer)\n"
443 "mainCRTStartup(HANDLE hInstance,\n"
444 " HANDLE hPrevInstance,\n"
445 " LPSTR lpszCmdParam,\n"
448 " InitializeTests();\n"
449 " RegisterTests();\n"
451 " PerformTests(ConsoleWrite, NULL);\n"
452 " _ExitProcess(0);\n"
456 static char STUBS_HEADER
[] =
457 "/* This file is autogenerated. */\n"
459 " call _FrameworkGetHook@4\n"
464 " /* This will most likely corrupt the stack */\n"
468 static char HOOKS_HEADER
[] =
469 "/* This file is autogenerated. */\n"
470 "#include <windows.h>\n"
471 "#include \"regtests.h\"\n"
473 "API_DESCRIPTION ExternalDependencies[] =\n"
476 static char HOOKS_FOOTER
[] =
479 "#define ExternalDependencyCount %d\n"
480 "ULONG MaxExternalDependency = ExternalDependencyCount - 1;\n";
483 "REGTESTS path file makefile [-e exestubfile]\n"
484 "REGTESTS -s stublistfile stubsfile hooksfile\n"
486 " path Path to files\n"
487 " file Registration file to create\n"
488 " makefile Makefile to create\n"
489 " exestubfile Optional stub for running tests in the build environment\n"
490 " stublistfile File with descriptions of stubs\n"
491 " stubsfile File with stubs to create\n"
492 " hooksfile File with hooks to create\n";
494 #define INPUT_BUFFER_SIZE 255
497 write_stubs_header(FILE * out
)
499 fputs(STUBS_HEADER
, out
);
503 write_hooks_header(FILE * out
)
505 fputs(HOOKS_HEADER
, out
);
509 write_hooks_footer(FILE *hooks_out
, unsigned long nr_stubs
)
511 fprintf(hooks_out
, HOOKS_FOOTER
, nr_stubs
);
515 get_symbolname(char *decoratedname
)
519 if (decoratedname
[0] == '@')
520 return strdup(decoratedname
);
522 strcat(buf
, decoratedname
);
527 get_undecorated_name(char *buf
,
533 while (start
< strlen(decoratedname
) && decoratedname
[start
] == '@')
537 strcpy(buf
, &decoratedname
[start
]);
538 end
= strlen(buf
) - 1;
539 while (end
> 0 && isdigit(buf
[end
]))
551 get_forwarded_export(char *forwardedexport
)
555 if (forwardedexport
== NULL
)
561 sprintf(buf
, "\"%s\"", forwardedexport
);
567 write_stub(FILE *stubs_out
, FILE *hooks_out
, char *dllname
,
568 char *decoratedname_and_forward
, unsigned int stub_index
)
572 char *decoratedname
= NULL
;
573 char *forwardedexport
= NULL
;
574 char *symbolname
= NULL
;
576 p
= strtok(decoratedname_and_forward
, "=");
581 p
= strtok(NULL
, "=");
586 decoratedname
= decoratedname_and_forward
;
587 forwardedexport
= decoratedname_and_forward
;
590 symbolname
= get_symbolname(decoratedname
);
591 fprintf(stubs_out
, ".globl %s\n", symbolname
);
592 fprintf(stubs_out
, "%s:\n", symbolname
);
594 fprintf(stubs_out
, " pushl $%d\n", stub_index
);
595 fprintf(stubs_out
, " jmp passthrough\n");
596 fprintf(stubs_out
, "\n");
597 forwardedexport
= get_forwarded_export(forwardedexport
);
598 fprintf(hooks_out
, " {\"%s\", \"%s\", %s, NULL, NULL},\n",
600 get_undecorated_name(buf
, decoratedname
),
602 free(forwardedexport
);
606 create_stubs_and_hooks(
611 char line
[INPUT_BUFFER_SIZE
];
614 char *decoratedname_and_forward
;
617 write_stubs_header(stubs_out
);
619 write_hooks_header(hooks_out
);
622 * Scan the database. The database is a text file; each
623 * line is a record, which contains data for one stub.
624 * Each record has two columns:
626 * DLLNAME (e.g. ntdll.dll)
627 * DECORATED NAME (e.g. NtCreateProcess@32, @InterlockedIncrement@4 or printf)
629 stub_index
= 0; /* First stub has index zero */
633 /* Go on until EOF or read zero bytes */
634 ((!feof(in
)) && (fgets(line
, sizeof line
, in
) != NULL
));
635 /* Next stub index */
639 * Remove, if present, the trailing LF.
641 if ((s
= (char *) strchr(line
,'\n')) != NULL
)
647 * Remove, if present, the trailing CR.
649 if ((s
= (char *) strchr(line
,'\r')) != NULL
)
655 * Skip comments (#) and empty lines.
658 if ((*s
) != '#' && (*s
) != '\0')
660 /* Extract the DLL name */
661 dllname
= (char *) strtok(s
, " \t");
662 if (dllname
!= NULL
&& strlen(dllname
) > 0)
665 * Extract the decorated function name and possibly forwarded export.
667 * decoratedname=forwardedexport (no DLL name)
669 decoratedname_and_forward
= (char *) strtok(NULL
, " \t");
670 /* Extract the argument count */
671 write_stub(stubs_out
, hooks_out
, dllname
, decoratedname_and_forward
, stub_index
);
677 write_hooks_footer(hooks_out
, stub_index
);
680 int run_stubs(int argc
,
687 in
= fopen(argv
[2], "rb");
690 perror("Failed to open stub description input file");
694 stubs_out
= fopen(argv
[3], "wb");
695 if (stubs_out
== NULL
)
697 perror("Failed to open stubs output file");
701 hooks_out
= fopen(argv
[4], "wb");
702 if (hooks_out
== NULL
)
704 perror("Failed to open hooks output file");
708 create_stubs_and_hooks(in
, stubs_out
, hooks_out
);
716 int run_registrations(int argc
,
728 strcpy(buf
, convert_path(argv
[1]));
729 if (buf
[strlen(buf
)] != DIR_SEPARATOR_CHAR
)
732 buf
[strlen(buf
)] = DIR_SEPARATOR_CHAR
;
738 printf("Missing path\n");
742 file
= convert_path(argv
[2]);
745 printf("Missing file\n");
749 makefile
= convert_path(argv
[3]);
750 if (makefile
[0] == 0)
752 printf("Missing makefile\n");
757 for (i
= 4; i
< argc
; i
++)
759 if (argv
[i
][0] == '-')
761 if (argv
[i
][1] == 'e')
763 exestubfile
= convert_path(argv
[++i
]);
764 if (exestubfile
[0] == 0)
766 printf("Missing exestubfile\n");
772 printf("Unknown switch -%c\n", argv
[i
][1]);
779 /* Registration file */
780 out
= fopen(file
, "wb");
783 perror("Cannot create output file");
787 write_line("/* This file is autogenerated. */");
789 write_line("typedef int (*TestRoutine)(int Command, char *Buffer);");
795 write_line("extern void AddTest(TestRoutine Routine);");
797 write_line("void RegisterTests()");
808 out
= fopen(makefile
, "wb");
811 perror("Cannot create output makefile");
815 write_line("# This file is autogenerated.");
817 write_line("TESTS = \\");
825 /* Executable stubfile */
826 if (exestubfile
!= NULL
)
828 if (write_file_if_changed(exestubfile
, EXESTUB
) != 0)
830 perror("Cannot create output executable stubfile");
847 if (strlen(argv
[1]) > 1 && argv
[1][0] == '-' && argv
[1][1] == 's')
849 return run_stubs(argc
, argv
);
853 return run_registrations(argc
, argv
);