2 * Generate a file with API status information from a list
3 * of files in a directory.
4 * Casper S. Hornstrup <chorns@users.sourceforge.net>
17 int __cdecl
strcasecmp (const char * __sz1
, const char * __sz2
)
18 {return _stricmp (__sz1
, __sz2
);}
20 #if !defined(__FreeBSD__) && !defined(__APPLE__)
24 #include <sys/types.h>
33 #define DIR_SEPARATOR_CHAR '/'
34 #define DIR_SEPARATOR_STRING "/"
36 #define DIR_SEPARATOR_CHAR '\\'
37 #define DIR_SEPARATOR_STRING "\\"
40 #define TAG_UNKNOWN -1
41 #define TAG_IMPLEMENTED 0
42 #define TAG_UNIMPLEMENTED 1
44 typedef struct _API_INFO
46 struct _API_INFO
*next
;
49 char filename
[MAX_PATH
];
50 } API_INFO
, *PAPI_INFO
;
53 PAPI_INFO
sort_linked_list(PAPI_INFO
,
54 unsigned, int (*)(PAPI_INFO
, PAPI_INFO
));
59 static FILE *file_handle
= NULL
;
60 static char *file_buffer
= NULL
;
61 static unsigned int file_size
= 0;
62 static int file_pointer
= 0;
63 static char tagname
[200];
64 static PAPI_INFO api_info_list
= NULL
;
68 convert_path(char* origpath
)
73 newpath
= strdup(origpath
);
76 while (newpath
[i
] != 0)
79 if (newpath
[i
] == '\\')
85 if (newpath
[i
] == '/')
97 path_to_url(char* path
)
114 write_line(char *line
)
119 memset(buf
, 0, sizeof(buf
));
121 /* Terminate the line */
122 buf
[strlen(buf
)] = '\r';
123 buf
[strlen(buf
)] = '\n';
125 n_out
= fwrite(&buf
[0], 1, strlen(buf
), out
);
130 read_file(char *filename
)
132 file_handle
= fopen(filename
, "rb");
133 if (file_handle
== NULL
)
135 printf("Can't open %s\n", filename
);
139 // Get the size of the file
140 fseek(file_handle
, 0, SEEK_END
);
141 file_size
= ftell(file_handle
);
143 // Load it all into memory
144 file_buffer
= malloc(file_size
);
145 if (file_buffer
== NULL
)
148 printf("Out of memory\n");
151 fseek(file_handle
, 0, SEEK_SET
);
154 if (fread (file_buffer
, 1, file_size
, file_handle
) < 1)
157 printf("Read error in file %s\n", filename
);
176 is_whitespace(char ch
)
204 is_end_of_tag(char ch
)
206 if ((ch
>= 'a') && (ch
<= 'z'))
210 if ((ch
>= 'A') && (ch
<= 'Z'))
214 if ((ch
>= '0') && (ch
<= '9'))
226 is_end_of_name(char ch
)
228 /* Currently the same as is_end_of_tag() */
229 return is_end_of_tag(ch
);
233 is_valid_file(char *filename
)
238 i
= strlen(filename
);
239 while (i
> 0 && filename
[i
] != '.')
245 memset(ext
, 0, sizeof(ext
));
246 strncpy(&ext
[0], &filename
[i
], strlen(&filename
[i
]));
248 if ((strncmp(ext
, ".c", 2) == 0) || (strncmp(ext
, ".C", 2) == 0))
257 get_tag_id(char *tag
)
259 if (strcasecmp(tag
, "implemented") == 0)
261 return TAG_IMPLEMENTED
;
263 if (strcasecmp(tag
, "unimplemented") == 0)
265 return TAG_UNIMPLEMENTED
;
280 while ((file_pointer
< file_size
) && (!found_tag
))
282 if (file_buffer
[file_pointer
] == '@')
285 start
= file_pointer
;
287 while ((file_pointer
< file_size
) && (!end_of_tag
))
289 end_of_tag
= is_end_of_tag(file_buffer
[file_pointer
]);
292 len
= file_pointer
> start
? file_pointer
- start
- 1 : 0;
293 strncpy(tagname
, &file_buffer
[start
], len
);
296 tag_id
= get_tag_id(tagname
);
297 if (tag_id
!= TAG_UNKNOWN
)
311 while ((file_pointer
< file_size
) && (!is_eol_char(file_buffer
[file_pointer
])))
315 if ((file_pointer
< file_size
) && (file_buffer
[file_pointer
] == '\n'))
324 while ((file_pointer
< file_size
))
326 if (file_buffer
[file_pointer
] == '*')
328 if ((file_pointer
+ 1 < file_size
))
330 if (file_buffer
[file_pointer
+ 1] == '/')
342 get_previous_identifier(unsigned int end
, char *name
)
344 unsigned int my_file_pointer
= end
;
349 while ((my_file_pointer
> 0) && (is_whitespace(file_buffer
[my_file_pointer
])
350 || is_eol_char(file_buffer
[my_file_pointer
])))
355 /* Skip any comments between function name and it's parameters */
356 if ((my_file_pointer
> 0) && (file_buffer
[my_file_pointer
] == '/'))
358 if ((my_file_pointer
> 0) && (file_buffer
[my_file_pointer
- 1] == '*'))
361 while ((my_file_pointer
> 0) && !((file_buffer
[my_file_pointer
] == '*')
362 && (file_buffer
[my_file_pointer
- 1] == '/')))
366 my_file_pointer
-= 2;
370 /* Skip any remaining whitespace */
371 while ((my_file_pointer
> 0) && (is_whitespace(file_buffer
[my_file_pointer
])))
376 end
= my_file_pointer
;
377 while ((my_file_pointer
> 0))
379 if (is_end_of_name(file_buffer
[my_file_pointer
]))
381 len
= end
- my_file_pointer
;
382 strncpy(name
, &file_buffer
[my_file_pointer
+ 1], len
);
393 skip_to_next_name(char *name
)
395 while ((file_pointer
< file_size
))
397 if (file_buffer
[file_pointer
] == '(')
399 return get_previous_identifier(file_pointer
- 1, name
);
406 // Build a path and filename so it is of the format [module][directory][filename].
407 // Also convert all backslashes into forward slashes.
409 get_filename(char *cvspath
, char *filename
, char *result
)
411 strcpy(result
, cvspath
);
412 strcat(result
, filename
);
417 parse_file(char *fullname
, char *cvspath
, char *filename
)
429 tag_id
= skip_to_next_tag();
430 if (tag_id
== TAG_UNKNOWN
)
435 /* Skip rest of the comments between the tag and the function name */
438 if (skip_to_next_name(name
))
440 if (strlen(name
) == 0)
442 printf("Warning: empty function name in file %s. Previous function name was %s.\n",
445 api_info
= malloc(sizeof(API_INFO
));
446 if (api_info
== NULL
)
448 printf("Out of memory\n");
452 api_info
->tag_id
= tag_id
;
453 strcpy(api_info
->name
, name
);
455 get_filename(cvspath
, filename
, api_info
->filename
);
457 api_info
->next
= api_info_list
;
458 api_info_list
= api_info
;
470 process_directory (char *path
, char *cvspath
)
472 struct _finddata_t f
;
474 char searchbuf
[MAX_PATH
];
476 char newcvspath
[MAX_PATH
];
478 strcpy(searchbuf
, path
);
479 strcat(searchbuf
, "*.*");
481 findhandle
=_findfirst(searchbuf
, &f
);
482 if (findhandle
!= -1)
486 if (f
.attrib
& _A_SUBDIR
)
488 if (f
.name
[0] != '.')
492 strcat(buf
, DIR_SEPARATOR_STRING
);
494 strcpy(newcvspath
, cvspath
);
495 strcat(newcvspath
, f
.name
);
496 strcat(newcvspath
, "/");
498 process_directory(buf
, newcvspath
);
506 /* Must be a .c file */
507 if (!is_valid_file(buf
))
512 parse_file(buf
, cvspath
, f
.name
);
514 while (_findnext(findhandle
, &f
) == 0);
515 _findclose(findhandle
);
519 printf("Cannot open directory '%s'", path
);
528 process_directory (char *path
, char *cvspath
)
531 struct dirent
*entry
;
534 char newcvspath
[MAX_PATH
];
537 dirp
= opendir(path
);
540 while ((entry
= readdir(dirp
)) != NULL
)
542 if (strcmp(entry
->d_name
, ".") == 0 || strcmp(entry
->d_name
, "..") == 0)
543 continue; // skip self and parent
545 if (entry
->d_type
== DT_REG
) // normal file
547 // Check for an absolute path
548 if (path
[0] == DIR_SEPARATOR_CHAR
)
551 strcat(buf
, DIR_SEPARATOR_STRING
);
552 strcat(buf
, entry
->d_name
);
556 if (!getcwd(buf
, sizeof(buf
)))
558 printf("Can't get CWD: %s\n", strerror(errno
));
561 strcat(buf
, DIR_SEPARATOR_STRING
);
563 strcat(buf
, entry
->d_name
);
566 if (stat(buf
, &stbuf
) == -1)
568 printf("Can't access '%s' (%s)\n", buf
, strerror(errno
));
572 if (S_ISDIR(stbuf
.st_mode
))
574 strcpy(newcvspath
, cvspath
);
575 strcat(newcvspath
, f
.name
);
576 strcat(newcvspath
, "/");
578 process_directory(buf
, newcvspath
);
582 /* Must be a .c file */
583 if (!is_valid_file(buf
))
588 parse_file(buf
, cvspath
, entry
->d_name
);
595 printf("Can't open %s\n", path
);
601 dirp
= opendir(path
);
604 while ((entry
= readdir(dirp
)) != NULL
)
606 if (strcmp(entry
->d_name
, ".") == 0 || strcmp(entry
->d_name
, "..") == 0)
607 continue; // skip self and parent
609 // Check for an absolute path
610 if (path
[0] == DIR_SEPARATOR_CHAR
)
613 strcat(buf
, DIR_SEPARATOR_STRING
);
614 strcat(buf
, entry
->d_name
);
618 if (!getcwd(buf
, sizeof(buf
)))
620 printf("Can't get CWD: %s\n", strerror(errno
));
623 strcat(buf
, DIR_SEPARATOR_STRING
);
625 strcat(buf
, entry
->d_name
);
628 if (stat(buf
, &stbuf
) == -1)
630 printf("Can't access '%s' (%s)\n", buf
, strerror(errno
));
634 if (S_ISDIR(stbuf
.st_mode
))
636 strcpy(newcvspath
, cvspath
);
637 strcat(newcvspath
, entry
->d_name
);
638 strcat(newcvspath
, "/");
640 process_directory(buf
, newcvspath
);
644 /* Must be a .c file */
645 if (!is_valid_file(buf
))
650 parse_file(buf
, cvspath
, entry
->d_name
);
656 printf("Can't open %s\n", path
);
666 * This function compares two API entries. It returns a negative value if p is
667 * before q, or a positive value if p is after q.
670 compare_api_order(PAPI_INFO p
, PAPI_INFO q
)
672 return strcmp(p
->name
, q
->name
);
676 get_filename_without_base(char *component_base
,
679 return &filename
[strlen(component_base
)];
683 generate_xml_for_component(char *component_name
,
684 char *component_base
)
687 char canonical_base
[MAX_PATH
];
690 int implemented_total
;
691 int unimplemented_total
;
694 api_info_list
= sort_linked_list(api_info_list
, 0, compare_api_order
);
696 implemented_total
= 0;
697 unimplemented_total
= 0;
699 api_info
= api_info_list
;
700 while (api_info
!= NULL
)
702 if (api_info
->tag_id
== TAG_IMPLEMENTED
)
703 implemented_total
++;
704 else if (api_info
->tag_id
== TAG_UNIMPLEMENTED
)
705 unimplemented_total
++;
707 api_info
= api_info
->next
;
710 if (implemented_total
+ unimplemented_total
> 0)
711 complete
= ((implemented_total
) * 100) / (implemented_total
+ unimplemented_total
);
715 strcpy(canonical_base
, component_base
);
716 path_to_url(canonical_base
);
718 sprintf(buf
, "<component name=\"%s\" base=\"%s\" complete=\"%d\" implemented_total=\"%d\" unimplemented_total=\"%d\">",
719 component_name
, canonical_base
, complete
, implemented_total
, unimplemented_total
);
722 if (api_info_list
!= NULL
)
724 write_line("<functions>");
726 api_info
= api_info_list
;
727 while (api_info
!= NULL
)
729 sprintf(buf
, "<f n=\"%s\" i=\"%s\" f=\"%s\" />",
731 api_info
->tag_id
== TAG_IMPLEMENTED
? "true" : "false",
732 get_filename_without_base(component_base
,
733 api_info
->filename
));
735 api_info
= api_info
->next
;
738 write_line("</functions>");
741 write_line("</component>");
745 read_input_file(char *input_file
)
747 char component_name
[MAX_PATH
];
748 char component_path
[MAX_PATH
];
749 char *canonical_path
;
753 PAPI_INFO next_api_info
;
758 in
= fopen(input_file
, "rb");
761 printf("Cannot open input file");
765 // Get the size of the file
766 fseek(in
, 0, SEEK_END
);
769 // Load it all into memory
770 buffer
= malloc(size
);
774 printf("Out of memory\n");
777 fseek(in
, 0, SEEK_SET
);
778 if (fread (buffer
, 1, size
, in
) < 1)
781 printf("Read error in file %s\n", input_file
);
787 write_line("<?xml version=\"1.0\" encoding=\"iso-8859-1\" ?>");
788 write_line("<?xml-stylesheet type=\"text/xsl\" href=\"rapistatus.xsl\"?>");
790 write_line("<components>");
794 /* Free previous list */
795 for (api_info
= api_info_list
; api_info
!= NULL
; api_info
= next_api_info
)
797 next_api_info
= api_info
->next
;
800 api_info_list
= NULL
;
802 /* Skip whitespace and eol characters */
803 while ((index
< size
) && (is_whitespace(buffer
[index
]) || (is_eol_char(buffer
[index
]))))
805 if ((file_pointer
< size
) && (buffer
[index
] == '\n'))
808 if (buffer
[index
] == ';')
811 while ((index
< size
) && (!is_eol_char(buffer
[index
])))
813 if ((index
< size
) && (buffer
[index
] == '\n'))
818 /* Get component name */
820 while ((index
< size
) && (!is_whitespace(buffer
[index
])))
826 strncpy(component_name
, &buffer
[start
], len
);
827 component_name
[len
] = 0;
829 /* Skip whitespace */
830 while ((index
< size
) && (is_whitespace(buffer
[index
])))
835 /* Get component path */
837 while ((index
< size
) && (!is_whitespace(buffer
[index
]) && !is_eol_char(buffer
[index
])))
841 strncpy(component_path
, &buffer
[start
], len
);
842 component_path
[len
] = 0;
844 /* Append directory separator if needed */
845 if (component_path
[strlen(component_path
)] != DIR_SEPARATOR_CHAR
)
847 int i
= strlen(component_path
);
848 component_path
[strlen(component_path
)] = DIR_SEPARATOR_CHAR
;
849 component_path
[i
+ 1] = 0;
852 /* Skip to end of line */
853 while ((index
< size
) && (!is_eol_char(buffer
[index
])))
855 if ((index
< size
) && (buffer
[index
] == '\n'))
858 canonical_path
= convert_path(component_path
);
859 if (canonical_path
!= NULL
)
861 process_directory(canonical_path
, canonical_path
);
862 free(canonical_path
);
863 generate_xml_for_component(component_name
,
868 write_line("</components>");
872 "RGENSTAT input-filename output-filename\n"
874 " input-filename File containing list of components to process\n"
875 " output-filename File to create\n";
877 int main(int argc
, char **argv
)
888 input_file
= convert_path(argv
[1]);
889 if (input_file
[0] == 0)
891 printf("Missing input-filename\n");
895 output_file
= convert_path(argv
[2]);
896 if (output_file
[0] == 0)
898 printf("Missing output-filename\n");
902 out
= fopen(output_file
, "wb");
905 printf("Cannot open output file");
909 read_input_file(input_file
);