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>
19 #include <sys/types.h>
27 #define DIR_SEPARATOR_CHAR '/'
28 #define DIR_SEPARATOR_STRING "/"
30 #define DIR_SEPARATOR_CHAR '\\'
31 #define DIR_SEPARATOR_STRING "\\"
34 #define TAG_UNKNOWN -1
35 #define TAG_IMPLEMENTED 0
36 #define TAG_UNIMPLEMENTED 1
38 typedef struct _API_INFO
40 struct _API_INFO
*next
;
43 char filename
[MAX_PATH
];
44 } API_INFO
, *PAPI_INFO
;
47 PAPI_INFO
sort_linked_list(PAPI_INFO
,
48 unsigned, int (*)(PAPI_INFO
, PAPI_INFO
));
54 static FILE *file_handle
= NULL
;
55 static char *file_buffer
= NULL
;
56 static unsigned int file_size
= 0;
57 static int file_pointer
= 0;
58 static char tagname
[200];
59 static PAPI_INFO api_info_list
= NULL
;
63 convert_path(char* origpath
)
68 newpath
= strdup(origpath
);
71 while (newpath
[i
] != 0)
74 if (newpath
[i
] == '\\')
80 if (newpath
[i
] == '/')
92 path_to_url(char* path
)
109 write_line(char *line
)
114 memset(buf
, 0, sizeof(buf
));
116 /* Terminate the line */
117 buf
[strlen(buf
)] = '\r';
118 buf
[strlen(buf
)] = '\n';
120 n_out
= fwrite(&buf
[0], 1, strlen(buf
), out
);
125 read_file(char *filename
)
127 file_handle
= fopen(filename
, "rb");
128 if (file_handle
== NULL
)
130 printf("Can't open %s\n", filename
);
134 // Get the size of the file
135 fseek(file_handle
, 0, SEEK_END
);
136 file_size
= ftell(file_handle
);
138 // Load it all into memory
139 file_buffer
= malloc(file_size
);
140 if (file_buffer
== NULL
)
143 printf("Out of memory\n");
146 fseek(file_handle
, 0, SEEK_SET
);
149 if (fread (file_buffer
, 1, file_size
, file_handle
) < 1)
152 printf("Read error in file %s\n", filename
);
171 is_whitespace(char ch
)
199 is_end_of_tag(char ch
)
201 if ((ch
>= 'a') && (ch
<= 'z'))
205 if ((ch
>= 'A') && (ch
<= 'Z'))
209 if ((ch
>= '0') && (ch
<= '9'))
221 is_end_of_name(char ch
)
223 /* Currently the same as is_end_of_tag() */
224 return is_end_of_tag(ch
);
228 is_valid_file(char *filename
)
233 i
= strlen(filename
);
234 while (i
> 0 && filename
[i
] != '.')
240 memset(ext
, 0, sizeof(ext
));
241 strncpy(&ext
[0], &filename
[i
], strlen(&filename
[i
]));
243 if ((strncmp(ext
, ".c", 2) == 0) || (strncmp(ext
, ".C", 2) == 0))
252 get_tag_id(char *tag
)
254 if (strcasecmp(tag
, "implemented") == 0)
256 return TAG_IMPLEMENTED
;
258 if (strcasecmp(tag
, "unimplemented") == 0)
260 return TAG_UNIMPLEMENTED
;
275 while ((file_pointer
< file_size
) && (!found_tag
))
277 if (file_buffer
[file_pointer
] == '@')
280 start
= file_pointer
;
282 while ((file_pointer
< file_size
) && (!end_of_tag
))
284 end_of_tag
= is_end_of_tag(file_buffer
[file_pointer
]);
287 len
= file_pointer
> start
? file_pointer
- start
- 1 : 0;
288 strncpy(tagname
, &file_buffer
[start
], len
);
291 tag_id
= get_tag_id(tagname
);
292 if (tag_id
!= TAG_UNKNOWN
)
306 while ((file_pointer
< file_size
) && (!is_eol_char(file_buffer
[file_pointer
])))
310 if ((file_pointer
< file_size
) && (file_buffer
[file_pointer
] == '\n'))
319 while ((file_pointer
< file_size
))
321 if (file_buffer
[file_pointer
] == '*')
323 if ((file_pointer
+ 1 < file_size
))
325 if (file_buffer
[file_pointer
+ 1] == '/')
337 get_previous_identifier(unsigned int end
, char *name
)
339 unsigned int my_file_pointer
= end
;
344 while ((my_file_pointer
> 0) && (is_whitespace(file_buffer
[my_file_pointer
])
345 || is_eol_char(file_buffer
[my_file_pointer
])))
350 /* Skip any comments between function name and it's parameters */
351 if ((my_file_pointer
> 0) && (file_buffer
[my_file_pointer
] == '/'))
353 if ((my_file_pointer
> 0) && (file_buffer
[my_file_pointer
- 1] == '*'))
356 while ((my_file_pointer
> 0) && !((file_buffer
[my_file_pointer
] == '*')
357 && (file_buffer
[my_file_pointer
- 1] == '/')))
361 my_file_pointer
-= 2;
365 /* Skip any remaining whitespace */
366 while ((my_file_pointer
> 0) && (is_whitespace(file_buffer
[my_file_pointer
])))
371 end
= my_file_pointer
;
372 while ((my_file_pointer
> 0))
374 if (is_end_of_name(file_buffer
[my_file_pointer
]))
376 len
= end
- my_file_pointer
;
377 strncpy(name
, &file_buffer
[my_file_pointer
+ 1], len
);
388 skip_to_next_name(char *name
)
390 while ((file_pointer
< file_size
))
392 if (file_buffer
[file_pointer
] == '(')
394 return get_previous_identifier(file_pointer
- 1, name
);
401 // Build a path and filename so it is of the format [cvs-module][directory][filename].
402 // Also convert all backslashes into forward slashes.
404 get_filename(char *cvspath
, char *filename
, char *result
)
406 strcpy(result
, cvspath
);
407 strcat(result
, filename
);
412 parse_file(char *fullname
, char *cvspath
, char *filename
)
424 tag_id
= skip_to_next_tag();
425 if (tag_id
== TAG_UNKNOWN
)
430 /* Skip rest of the comments between the tag and the function name */
433 if (skip_to_next_name(name
))
435 if (strlen(name
) == 0)
437 printf("Warning: empty function name in file %s. Previous function name was %s.\n",
440 api_info
= malloc(sizeof(API_INFO
));
441 if (api_info
== NULL
)
443 printf("Out of memory\n");
447 api_info
->tag_id
= tag_id
;
448 strcpy(api_info
->name
, name
);
450 get_filename(cvspath
, filename
, api_info
->filename
);
452 api_info
->next
= api_info_list
;
453 api_info_list
= api_info
;
465 process_directory (char *path
, char *cvspath
)
467 struct _finddata_t f
;
469 char searchbuf
[MAX_PATH
];
471 char newcvspath
[MAX_PATH
];
473 strcpy(searchbuf
, path
);
474 strcat(searchbuf
, "*.*");
476 findhandle
=_findfirst(searchbuf
, &f
);
477 if (findhandle
!= -1)
481 if (f
.attrib
& _A_SUBDIR
)
483 if (f
.name
[0] != '.')
487 strcat(buf
, DIR_SEPARATOR_STRING
);
489 strcpy(newcvspath
, cvspath
);
490 strcat(newcvspath
, f
.name
);
491 strcat(newcvspath
, "/");
493 process_directory(buf
, newcvspath
);
501 /* Must be a .c file */
502 if (!is_valid_file(buf
))
507 parse_file(buf
, cvspath
, f
.name
);
509 while (_findnext(findhandle
, &f
) == 0);
510 _findclose(findhandle
);
514 printf("Cannot open directory '%s'", path
);
523 process_directory (char *path
, char *cvspath
)
526 struct dirent
*entry
;
529 char newcvspath
[MAX_PATH
];
532 dirp
= opendir(path
);
535 while ((entry
= readdir(dirp
)) != NULL
)
537 if (strcmp(entry
->d_name
, ".") == 0 || strcmp(entry
->d_name
, "..") == 0)
538 continue; // skip self and parent
540 if (entry
->d_type
== DT_REG
) // normal file
542 // Check for an absolute path
543 if (path
[0] == DIR_SEPARATOR_CHAR
)
546 strcat(buf
, DIR_SEPARATOR_STRING
);
547 strcat(buf
, entry
->d_name
);
551 getcwd(buf
, sizeof(buf
));
552 strcat(buf
, DIR_SEPARATOR_STRING
);
554 strcat(buf
, entry
->d_name
);
557 if (stat(buf
, &stbuf
) == -1)
559 printf("Can't access '%s' (%s)\n", buf
, strerror(errno
));
563 if (S_ISDIR(stbuf
.st_mode
))
565 strcpy(newcvspath
, cvspath
);
566 strcat(newcvspath
, f
.name
);
567 strcat(newcvspath
, "/");
569 process_directory(buf
, newcvspath
);
573 /* Must be a .c file */
574 if (!is_valid_file(buf
))
579 parse_file(buf
, cvspath
, entry
->d_name
);
586 printf("Can't open %s\n", path
);
592 dirp
= opendir(path
);
595 while ((entry
= readdir(dirp
)) != NULL
)
597 if (strcmp(entry
->d_name
, ".") == 0 || strcmp(entry
->d_name
, "..") == 0)
598 continue; // skip self and parent
600 // Check for an absolute path
601 if (path
[0] == DIR_SEPARATOR_CHAR
)
604 strcat(buf
, DIR_SEPARATOR_STRING
);
605 strcat(buf
, entry
->d_name
);
609 getcwd(buf
, sizeof(buf
));
610 strcat(buf
, DIR_SEPARATOR_STRING
);
612 strcat(buf
, entry
->d_name
);
615 if (stat(buf
, &stbuf
) == -1)
617 printf("Can't access '%s' (%s)\n", buf
, strerror(errno
));
621 if (S_ISDIR(stbuf
.st_mode
))
623 strcpy(newcvspath
, cvspath
);
624 strcat(newcvspath
, entry
->d_name
);
625 strcat(newcvspath
, "/");
627 process_directory(buf
, newcvspath
);
631 /* Must be a .c file */
632 if (!is_valid_file(buf
))
637 parse_file(buf
, cvspath
, entry
->d_name
);
643 printf("Can't open %s\n", path
);
653 * This function compares two API entries. It returns a negative value if p is
654 * before q, or a positive value if p is after q.
657 compare_api_order(PAPI_INFO p
, PAPI_INFO q
)
659 return strcmp(p
->name
, q
->name
);
663 generate_xml_for_component(char *component_name
)
669 int implemented_total
;
670 int unimplemented_total
;
673 api_info_list
= sort_linked_list(api_info_list
, 0, compare_api_order
);
675 implemented_total
= 0;
676 unimplemented_total
= 0;
678 api_info
= api_info_list
;
679 while (api_info
!= NULL
)
681 if (api_info
->tag_id
== TAG_IMPLEMENTED
)
683 implemented_total
++;
685 else if (api_info
->tag_id
== TAG_UNIMPLEMENTED
)
687 unimplemented_total
++;
690 api_info
= api_info
->next
;
693 if (implemented_total
+ unimplemented_total
> 0)
695 complete
= ((implemented_total
) * 100) / (implemented_total
+ unimplemented_total
);
702 sprintf(buf
, "<component name=\"%s\" complete=\"%d\" implemented_total=\"%d\" unimplemented_total=\"%d\">",
703 component_name
, complete
, implemented_total
, unimplemented_total
);
706 if (api_info_list
!= NULL
)
708 write_line("<functions>");
710 api_info
= api_info_list
;
711 while (api_info
!= NULL
)
713 sprintf(buf
, "<function name=\"%s\" implemented=\"%s\" file=\"%s\">",
715 api_info
->tag_id
== TAG_IMPLEMENTED
? "true" : "false",
718 write_line("</function>");
719 api_info
= api_info
->next
;
722 write_line("</functions>");
725 write_line("</component>");
729 read_input_file(char *input_file
)
731 char component_name
[MAX_PATH
];
732 char component_path
[MAX_PATH
];
733 char *canonical_path
;
737 PAPI_INFO next_api_info
;
742 in
= fopen(input_file
, "rb");
745 printf("Cannot open input file");
749 // Get the size of the file
750 fseek(in
, 0, SEEK_END
);
753 // Load it all into memory
754 buffer
= malloc(size
);
758 printf("Out of memory\n");
761 fseek(in
, 0, SEEK_SET
);
762 if (fread (buffer
, 1, size
, in
) < 1)
765 printf("Read error in file %s\n", input_file
);
771 write_line("<?xml version=\"1.0\" encoding=\"iso-8859-1\" ?>");
773 write_line("<components>");
777 /* Free previous list */
778 for (api_info
= api_info_list
; api_info
!= NULL
; api_info
= next_api_info
)
780 next_api_info
= api_info
->next
;
783 api_info_list
= NULL
;
785 /* Skip whitespace and eol characters */
786 while ((index
< size
) && (is_whitespace(buffer
[index
]) || (is_eol_char(buffer
[index
]))))
790 if ((file_pointer
< size
) && (buffer
[index
] == '\n'))
795 if (buffer
[index
] == ';')
798 while ((index
< size
) && (!is_eol_char(buffer
[index
])))
802 if ((index
< size
) && (buffer
[index
] == '\n'))
809 /* Get component name */
811 while ((index
< size
) && (!is_whitespace(buffer
[index
])))
821 strncpy(component_name
, &buffer
[start
], len
);
822 component_name
[len
] = 0;
824 /* Skip whitespace */
825 while ((index
< size
) && (is_whitespace(buffer
[index
])))
834 /* Get component path */
836 while ((index
< size
) && (!is_whitespace(buffer
[index
]) && !is_eol_char(buffer
[index
])))
842 strncpy(component_path
, &buffer
[start
], len
);
843 component_path
[len
] = 0;
845 /* Append directory separator if needed */
846 if (component_path
[strlen(component_path
)] != DIR_SEPARATOR_CHAR
)
848 int i
= strlen(component_path
);
849 component_path
[strlen(component_path
)] = DIR_SEPARATOR_CHAR
;
850 component_path
[i
+ 1] = 0;
853 /* Skip to end of line */
854 while ((index
< size
) && (!is_eol_char(buffer
[index
])))
858 if ((index
< size
) && (buffer
[index
] == '\n'))
863 canonical_path
= convert_path(component_path
);
864 if (canonical_path
!= NULL
)
866 process_directory(canonical_path
, canonical_path
);
867 free(canonical_path
);
868 generate_xml_for_component(component_name
);
872 write_line("</components>");
876 "RGENSTAT input-filename output-filename\n"
878 " input-filename File containing list of components to process\n"
879 " output-filename File to create\n";
881 int main(int argc
, char **argv
)
893 input_file
= convert_path(argv
[1]);
894 if (input_file
[0] == 0)
896 printf("Missing input-filename\n");
900 output_file
= convert_path(argv
[2]);
901 if (output_file
[0] == 0)
903 printf("Missing output-filename\n");
907 out
= fopen(output_file
, "wb");
910 printf("Cannot open output file");
914 read_input_file(input_file
);