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 } API_INFO
, *PAPI_INFO
;
46 PAPI_INFO
sort_linked_list(PAPI_INFO
,
47 unsigned, int (*)(PAPI_INFO
, PAPI_INFO
));
53 static FILE *file_handle
= NULL
;
54 static char *file_buffer
= NULL
;
55 static unsigned int file_size
= 0;
56 static int file_pointer
= 0;
57 static char tagname
[200];
58 static PAPI_INFO api_info_list
= NULL
;
62 convert_path(char* origpath
)
67 newpath
= strdup(origpath
);
70 while (newpath
[i
] != 0)
73 if (newpath
[i
] == '\\')
79 if (newpath
[i
] == '/')
91 write_line(char *line
)
96 memset(buf
, 0, sizeof(buf
));
98 /* Terminate the line */
99 buf
[strlen(buf
)] = '\r';
100 buf
[strlen(buf
)] = '\n';
102 n_out
= fwrite(&buf
[0], 1, strlen(buf
), out
);
107 read_file(char *filename
)
109 file_handle
= fopen(filename
, "rb");
110 if (file_handle
== NULL
)
112 printf("Can't open %s\n", filename
);
116 // Get the size of the file
117 fseek(file_handle
, 0, SEEK_END
);
118 file_size
= ftell(file_handle
);
120 // Load it all into memory
121 file_buffer
= malloc(file_size
);
122 if (file_buffer
== NULL
)
125 printf("Out of memory\n");
128 fseek(file_handle
, 0, SEEK_SET
);
131 if (fread (file_buffer
, 1, file_size
, file_handle
) < 1)
134 printf("Read error in file %s\n", filename
);
153 is_whitespace(char ch
)
181 is_end_of_tag(char ch
)
183 if ((ch
>= 'a') && (ch
<= 'z'))
187 if ((ch
>= 'A') && (ch
<= 'Z'))
191 if ((ch
>= '0') && (ch
<= '9'))
203 is_end_of_name(char ch
)
205 /* Currently the same as is_end_of_tag() */
206 return is_end_of_tag(ch
);
210 is_valid_file(char *filename
)
215 i
= strlen(filename
);
216 while (i
> 0 && filename
[i
] != '.')
222 memset(ext
, 0, sizeof(ext
));
223 strncpy(&ext
[0], &filename
[i
], strlen(&filename
[i
]));
225 if ((strncmp(ext
, ".c", 2) == 0) || (strncmp(ext
, ".C", 2) == 0))
234 get_tag_id(char *tag
)
236 if (strcasecmp(tag
, "implemented") == 0)
238 return TAG_IMPLEMENTED
;
240 if (strcasecmp(tag
, "unimplemented") == 0)
242 return TAG_UNIMPLEMENTED
;
257 while ((file_pointer
< file_size
) && (!found_tag
))
259 if (file_buffer
[file_pointer
] == '@')
262 start
= file_pointer
;
264 while ((file_pointer
< file_size
) && (!end_of_tag
))
266 end_of_tag
= is_end_of_tag(file_buffer
[file_pointer
]);
269 len
= file_pointer
> start
? file_pointer
- start
- 1 : 0;
270 strncpy(tagname
, &file_buffer
[start
], len
);
273 tag_id
= get_tag_id(tagname
);
274 if (tag_id
!= TAG_UNKNOWN
)
288 while ((file_pointer
< file_size
) && (!is_eol_char(file_buffer
[file_pointer
])))
292 if ((file_pointer
< file_size
) && (file_buffer
[file_pointer
] == '\n'))
301 while ((file_pointer
< file_size
))
303 if (file_buffer
[file_pointer
] == '*')
305 if ((file_pointer
+ 1 < file_size
))
307 if (file_buffer
[file_pointer
+ 1] == '/')
319 get_previous_identifier(unsigned int end
, char *name
)
321 unsigned int my_file_pointer
= end
;
326 while ((my_file_pointer
> 0) && (is_whitespace(file_buffer
[my_file_pointer
])
327 || is_eol_char(file_buffer
[my_file_pointer
])))
332 /* Skip any comments between function name and it's parameters */
333 if ((my_file_pointer
> 0) && (file_buffer
[my_file_pointer
] == '/'))
335 if ((my_file_pointer
> 0) && (file_buffer
[my_file_pointer
- 1] == '*'))
338 while ((my_file_pointer
> 0) && !((file_buffer
[my_file_pointer
] == '*')
339 && (file_buffer
[my_file_pointer
- 1] == '/')))
343 my_file_pointer
-= 2;
347 /* Skip any remaining whitespace */
348 while ((my_file_pointer
> 0) && (is_whitespace(file_buffer
[my_file_pointer
])))
353 end
= my_file_pointer
;
354 while ((my_file_pointer
> 0))
356 if (is_end_of_name(file_buffer
[my_file_pointer
]))
358 len
= end
- my_file_pointer
;
359 strncpy(name
, &file_buffer
[my_file_pointer
+ 1], len
);
370 skip_to_next_name(char *name
)
372 while ((file_pointer
< file_size
))
374 if (file_buffer
[file_pointer
] == '(')
376 return get_previous_identifier(file_pointer
- 1, name
);
384 parse_file(char *filename
)
396 tag_id
= skip_to_next_tag();
397 if (tag_id
== TAG_UNKNOWN
)
402 /* Skip rest of the comments between the tag and the function name */
405 if (skip_to_next_name(name
))
407 if (strlen(name
) == 0)
409 printf("Warning: empty function name in file %s. Previous function name was %s.\n",
412 api_info
= malloc(sizeof(API_INFO
));
413 if (api_info
== NULL
)
415 printf("Out of memory\n");
419 api_info
->tag_id
= tag_id
;
420 strcpy(api_info
->name
, name
);
422 api_info
->next
= api_info_list
;
423 api_info_list
= api_info
;
435 process_directory (char *path
)
437 struct _finddata_t f
;
439 char searchbuf
[MAX_PATH
];
442 printf("Processing '%s'\n", path
);
444 strcpy(searchbuf
, path
);
445 strcat(searchbuf
, "*.*");
447 findhandle
=_findfirst(searchbuf
, &f
);
448 if (findhandle
!= -1)
452 if (f
.attrib
& _A_SUBDIR
)
454 if (f
.name
[0] != '.')
458 strcat(buf
, DIR_SEPARATOR_STRING
);
459 process_directory(buf
);
467 /* Must be a .c file */
468 if (!is_valid_file(buf
))
475 while (_findnext(findhandle
, &f
) == 0);
476 _findclose(findhandle
);
480 printf("Cannot open directory '%s'", path
);
489 process_directory (char *path
)
492 struct dirent
*entry
;
497 dirp
= opendir(path
);
500 while ((entry
= readdir(dirp
)) != NULL
)
502 if (strcmp(entry
->d_name
, ".") == 0 || strcmp(entry
->d_name
, "..") == 0)
503 continue; // skip self and parent
505 if (entry
->d_type
== DT_REG
) // normal file
507 // Check for an absolute path
508 if (path
[0] == DIR_SEPARATOR_CHAR
)
511 strcat(buf
, DIR_SEPARATOR_STRING
);
512 strcat(buf
, entry
->d_name
);
516 getcwd(buf
, sizeof(buf
));
517 strcat(buf
, DIR_SEPARATOR_STRING
);
519 strcat(buf
, entry
->d_name
);
522 if (stat(buf
, &stbuf
) == -1)
524 printf("Can't access '%s' (%s)\n", buf
, strerror(errno
));
528 if (S_ISDIR(stbuf
.st_mode
))
530 process_directory(buf
);
534 /* Must be a .c file */
535 if (!is_valid_file(buf
))
547 printf("Can't open %s\n", path
);
553 dirp
= opendir(path
);
556 while ((entry
= readdir(dirp
)) != NULL
)
558 if (strcmp(entry
->d_name
, ".") == 0 || strcmp(entry
->d_name
, "..") == 0)
559 continue; // skip self and parent
561 // Check for an absolute path
562 if (path
[0] == DIR_SEPARATOR_CHAR
)
565 strcat(buf
, DIR_SEPARATOR_STRING
);
566 strcat(buf
, entry
->d_name
);
570 getcwd(buf
, sizeof(buf
));
571 strcat(buf
, DIR_SEPARATOR_STRING
);
573 strcat(buf
, entry
->d_name
);
576 if (stat(buf
, &stbuf
) == -1)
578 printf("Can't access '%s' (%s)\n", buf
, strerror(errno
));
582 if (S_ISDIR(stbuf
.st_mode
))
584 process_directory(buf
);
588 /* Must be a .c file */
589 if (!is_valid_file(buf
))
600 printf("Can't open %s\n", path
);
610 * This function compares two API entries. It returns a negative value if p is
611 * before q, or a positive value if p is after q.
614 compare_api_order(PAPI_INFO p
, PAPI_INFO q
)
616 return strcmp(p
->name
, q
->name
);
620 generate_xml_for_component(char *component_name
)
626 int implemented_total
;
627 int unimplemented_total
;
630 api_info_list
= sort_linked_list(api_info_list
, 0, compare_api_order
);
632 implemented_total
= 0;
633 unimplemented_total
= 0;
635 api_info
= api_info_list
;
636 while (api_info
!= NULL
)
638 if (api_info
->tag_id
== TAG_IMPLEMENTED
)
640 implemented_total
++;
642 else if (api_info
->tag_id
== TAG_UNIMPLEMENTED
)
644 unimplemented_total
++;
647 api_info
= api_info
->next
;
650 if (implemented_total
+ unimplemented_total
> 0)
652 complete
= ((implemented_total
) * 100) / (implemented_total
+ unimplemented_total
);
659 sprintf(buf
, "<component name=\"%s\" complete=\"%d\" implemented_total=\"%d\" unimplemented_total=\"%d\">",
660 component_name
, complete
, implemented_total
, unimplemented_total
);
663 if (api_info_list
!= NULL
)
665 write_line("<functions>");
667 api_info
= api_info_list
;
668 while (api_info
!= NULL
)
670 sprintf(buf
, "<function name=\"%s\" implemented=\"%s\">",
671 api_info
->name
, api_info
->tag_id
== TAG_IMPLEMENTED
? "true" : "false");
673 write_line("</function>");
674 api_info
= api_info
->next
;
677 write_line("</functions>");
680 write_line("</component>");
684 read_input_file(char *input_file
)
686 char component_name
[MAX_PATH
];
687 char component_path
[MAX_PATH
];
688 char *canonical_path
;
692 PAPI_INFO next_api_info
;
697 in
= fopen(input_file
, "rb");
700 printf("Cannot open input file");
704 // Get the size of the file
705 fseek(in
, 0, SEEK_END
);
708 // Load it all into memory
709 buffer
= malloc(size
);
713 printf("Out of memory\n");
716 fseek(in
, 0, SEEK_SET
);
717 if (fread (buffer
, 1, size
, in
) < 1)
720 printf("Read error in file %s\n", input_file
);
726 write_line("<?xml version=\"1.0\" encoding=\"iso-8859-1\" ?>");
728 write_line("<components>");
732 /* Free previous list */
733 for (api_info
= api_info_list
; api_info
!= NULL
; api_info
= next_api_info
)
735 next_api_info
= api_info
->next
;
738 api_info_list
= NULL
;
740 /* Skip whitespace and eol characters */
741 while ((index
< size
) && (is_whitespace(buffer
[index
]) || (is_eol_char(buffer
[index
]))))
745 if ((file_pointer
< size
) && (buffer
[index
] == '\n'))
750 if (buffer
[index
] == ';')
753 while ((index
< size
) && (!is_eol_char(buffer
[index
])))
757 if ((index
< size
) && (buffer
[index
] == '\n'))
764 /* Get component name */
766 while ((index
< size
) && (!is_whitespace(buffer
[index
])))
776 strncpy(component_name
, &buffer
[start
], len
);
777 component_name
[len
] = 0;
779 /* Skip whitespace */
780 while ((index
< size
) && (is_whitespace(buffer
[index
])))
789 /* Get component path */
791 while ((index
< size
) && (!is_whitespace(buffer
[index
]) && !is_eol_char(buffer
[index
])))
797 strncpy(component_path
, &buffer
[start
], len
);
798 component_path
[len
] = 0;
800 /* Append directory separator if needed */
801 if (component_path
[strlen(component_path
)] != DIR_SEPARATOR_CHAR
)
803 int i
= strlen(component_path
);
804 component_path
[strlen(component_path
)] = DIR_SEPARATOR_CHAR
;
805 component_path
[i
+ 1] = 0;
808 /* Skip to end of line */
809 while ((index
< size
) && (!is_eol_char(buffer
[index
])))
813 if ((index
< size
) && (buffer
[index
] == '\n'))
818 canonical_path
= convert_path(component_path
);
819 if (canonical_path
!= NULL
)
821 process_directory(canonical_path
);
822 free(canonical_path
);
823 generate_xml_for_component(component_name
);
827 write_line("</components>");
831 "RGENSTAT input-filename output-filename\n"
833 " input-filename File containing list of components to process\n"
834 " output-filename File to create\n";
836 int main(int argc
, char **argv
)
848 input_file
= convert_path(argv
[1]);
849 if (input_file
[0] == 0)
851 printf("Missing input-filename\n");
855 output_file
= convert_path(argv
[2]);
856 if (output_file
[0] == 0)
858 printf("Missing output-filename\n");
862 out
= fopen(output_file
, "wb");
865 printf("Cannot open output file");
869 read_input_file(input_file
);